summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/oss/pcm_oss.c3
-rw-r--r--sound/core/pcm_native.c11
-rw-r--r--sound/core/seq/seq_clientmgr.c103
-rw-r--r--sound/core/seq/seq_memory.c1
-rw-r--r--sound/core/seq/seq_ump_convert.c18
-rw-r--r--sound/core/seq/seq_ump_convert.h1
-rw-r--r--sound/core/seq_device.c2
-rw-r--r--sound/core/timer.c147
-rw-r--r--sound/hda/hda_bus_type.c6
-rw-r--r--sound/hda/intel-dsp-config.c5
-rw-r--r--sound/isa/ad1816a/ad1816a.c2
-rw-r--r--sound/isa/sb/sb16_main.c7
-rw-r--r--sound/pci/es1968.c6
-rw-r--r--sound/pci/hda/Kconfig5
-rw-r--r--sound/pci/hda/cs35l41_hda_property.c6
-rw-r--r--sound/pci/hda/hda_beep.c15
-rw-r--r--sound/pci/hda/hda_bind.c6
-rw-r--r--sound/pci/hda/hda_intel.c53
-rw-r--r--sound/pci/hda/hda_tegra.c51
-rw-r--r--sound/pci/hda/patch_hdmi.c20
-rw-r--r--sound/pci/hda/patch_realtek.c408
-rw-r--r--sound/sh/Kconfig2
-rw-r--r--sound/soc/amd/acp/acp-i2s.c2
-rw-r--r--sound/soc/amd/acp/acp-legacy-common.c10
-rw-r--r--sound/soc/amd/acp/acp-sdw-sof-mach.c2
-rw-r--r--sound/soc/amd/ps/acp63.h1
-rw-r--r--sound/soc/amd/ps/pci-ps.c2
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c58
-rw-r--r--sound/soc/apple/mca.c23
-rw-r--r--sound/soc/codecs/Kconfig5
-rw-r--r--sound/soc/codecs/arizona.c14
-rw-r--r--sound/soc/codecs/cs35l41-spi.c5
-rw-r--r--sound/soc/codecs/cs35l56-shared.c2
-rw-r--r--sound/soc/codecs/cs42l43-jack.c10
-rw-r--r--sound/soc/codecs/cs42l43.c2
-rw-r--r--sound/soc/codecs/hda.c4
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c117
-rw-r--r--sound/soc/codecs/madera.c10
-rw-r--r--sound/soc/codecs/mt6359-accdet.h9
-rw-r--r--sound/soc/codecs/pcm3168a.c6
-rw-r--r--sound/soc/codecs/pcm6240.c28
-rw-r--r--sound/soc/codecs/pcm6240.h7
-rw-r--r--sound/soc/codecs/rt1320-sdw.c20
-rw-r--r--sound/soc/codecs/rt5665.c24
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c53
-rw-r--r--sound/soc/codecs/tas2764.c111
-rw-r--r--sound/soc/codecs/tas2764.h11
-rw-r--r--sound/soc/codecs/tas2770.c32
-rw-r--r--sound/soc/codecs/wcd9335.c40
-rw-r--r--sound/soc/codecs/wcd934x.c2
-rw-r--r--sound/soc/codecs/wcd937x.c9
-rw-r--r--sound/soc/codecs/wm0010.c13
-rw-r--r--sound/soc/codecs/wm5110.c8
-rw-r--r--sound/soc/codecs/wsa883x.c2
-rw-r--r--sound/soc/codecs/wsa884x.c6
-rw-r--r--sound/soc/dwc/dwc-i2s.c13
-rw-r--r--sound/soc/fsl/fsl_asrc.c3
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c15
-rw-r--r--sound/soc/fsl/fsl_audmix.c16
-rw-r--r--sound/soc/fsl/fsl_qmc_audio.c3
-rw-r--r--sound/soc/fsl/fsl_sai.c14
-rw-r--r--sound/soc/fsl/imx-card.c6
-rw-r--r--sound/soc/generic/simple-card-utils.c5
-rw-r--r--sound/soc/intel/avs/debugfs.c6
-rw-r--r--sound/soc/intel/avs/ipc.c4
-rw-r--r--sound/soc/intel/avs/pcm.c3
-rw-r--r--sound/soc/intel/boards/Kconfig1
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c13
-rw-r--r--sound/soc/intel/boards/sof_sdw.c34
-rw-r--r--sound/soc/intel/common/Makefile2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c29
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-arl-match.c66
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c2
-rw-r--r--sound/soc/intel/common/sof-function-topology-lib.c136
-rw-r--r--sound/soc/intel/common/sof-function-topology-lib.h15
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-clk.c8
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-clk.h8
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-pcm.c4
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-mt6359.c4
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-dai-i2s.c3
-rw-r--r--sound/soc/meson/meson-card-utils.c2
-rw-r--r--sound/soc/qcom/lpass.h3
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-dai.c60
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c18
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.h3
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c19
-rw-r--r--sound/soc/qcom/sdm845.c4
-rw-r--r--sound/soc/qcom/sm8250.c3
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs42l43.c10
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt_amp.c2
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt_dmic.c2
-rw-r--r--sound/soc/sh/rcar/core.c14
-rw-r--r--sound/soc/sh/rcar/rsnd.h1
-rw-r--r--sound/soc/sh/rcar/src.c116
-rw-r--r--sound/soc/sh/rcar/ssi.c3
-rw-r--r--sound/soc/soc-core.c32
-rw-r--r--sound/soc/soc-dai.c8
-rw-r--r--sound/soc/soc-ops.c44
-rw-r--r--sound/soc/soc-pcm.c5
-rw-r--r--sound/soc/sof/amd/acp-ipc.c23
-rw-r--r--sound/soc/sof/amd/acp.c1
-rw-r--r--sound/soc/sof/amd/acp.h1
-rw-r--r--sound/soc/sof/amd/pci-acp70.c1
-rw-r--r--sound/soc/sof/amd/vangogh.c18
-rw-r--r--sound/soc/sof/intel/hda-bus.c2
-rw-r--r--sound/soc/sof/intel/hda-codec.c1
-rw-r--r--sound/soc/sof/intel/hda.c40
-rw-r--r--sound/soc/sof/intel/pci-ptl.c1
-rw-r--r--sound/soc/sof/ipc4-control.c11
-rw-r--r--sound/soc/sof/ipc4-pcm.c6
-rw-r--r--sound/soc/sof/topology.c22
-rw-r--r--sound/soc/sunxi/sun4i-codec.c53
-rw-r--r--sound/soc/tegra/tegra210_ahub.c2
-rw-r--r--sound/soc/ti/j721e-evm.c2
-rw-r--r--sound/soc/ti/omap-hdmi.c7
-rw-r--r--sound/usb/endpoint.c7
-rw-r--r--sound/usb/format.c3
-rw-r--r--sound/usb/implicit.c1
-rw-r--r--sound/usb/midi.c96
-rw-r--r--sound/usb/mixer_maps.c12
-rw-r--r--sound/usb/mixer_quirks.c51
-rw-r--r--sound/usb/quirks.c6
-rw-r--r--sound/usb/stream.c2
-rw-r--r--sound/usb/usx2y/usbusx2y.c11
-rw-r--r--sound/usb/usx2y/usbusx2y.h26
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c27
-rw-r--r--sound/virtio/virtio_pcm.c21
127 files changed, 2138 insertions, 604 deletions
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 4683b9139c56..4ecb17bd5436 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -1074,8 +1074,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
runtime->oss.params = 0;
runtime->oss.prepare = 1;
runtime->oss.buffer_used = 0;
- if (runtime->dma_area)
- snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
+ snd_pcm_runtime_buffer_set_silence(runtime);
runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 0790b5fd917e..0a1ba26872f8 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -723,6 +723,17 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime)
atomic_inc(&runtime->buffer_accessing);
}
+/* fill the PCM buffer with the current silence format; called from pcm_oss.c */
+void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime)
+{
+ snd_pcm_buffer_access_lock(runtime);
+ if (runtime->dma_area)
+ snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+ bytes_to_samples(runtime, runtime->dma_bytes));
+ snd_pcm_buffer_access_unlock(runtime);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence);
+
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
#define is_oss_stream(substream) ((substream)->oss.oss)
#else
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 9955c4d54e42..9e59a97f4747 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -106,7 +106,7 @@ static struct snd_seq_client *clientptr(int clientid)
return clienttab[clientid];
}
-struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
+static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
{
unsigned long flags;
struct snd_seq_client *client;
@@ -126,7 +126,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
}
spin_unlock_irqrestore(&clients_lock, flags);
#ifdef CONFIG_MODULES
- if (!in_interrupt()) {
+ if (load_module) {
static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS);
static DECLARE_BITMAP(card_requested, SNDRV_CARDS);
@@ -168,6 +168,20 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
return client;
}
+/* get snd_seq_client object for the given id quickly */
+struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
+{
+ return client_use_ptr(clientid, false);
+}
+
+/* get snd_seq_client object for the given id;
+ * if not found, retry after loading the modules
+ */
+static struct snd_seq_client *client_load_and_use_ptr(int clientid)
+{
+ return client_use_ptr(clientid, IS_ENABLED(CONFIG_MODULES));
+}
+
/* Take refcount and perform ioctl_mutex lock on the given client;
* used only for OSS sequencer
* Unlock via snd_seq_client_ioctl_unlock() below
@@ -176,7 +190,7 @@ bool snd_seq_client_ioctl_lock(int clientid)
{
struct snd_seq_client *client;
- client = snd_seq_client_use_ptr(clientid);
+ client = client_load_and_use_ptr(clientid);
if (!client)
return false;
mutex_lock(&client->ioctl_mutex);
@@ -718,15 +732,21 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
*/
static int __deliver_to_subscribers(struct snd_seq_client *client,
struct snd_seq_event *event,
- struct snd_seq_client_port *src_port,
- int atomic, int hop)
+ int port, int atomic, int hop)
{
+ struct snd_seq_client_port *src_port;
struct snd_seq_subscribers *subs;
int err, result = 0, num_ev = 0;
union __snd_seq_event event_saved;
size_t saved_size;
struct snd_seq_port_subs_info *grp;
+ if (port < 0)
+ return 0;
+ src_port = snd_seq_port_use_ptr(client, port);
+ if (!src_port)
+ return 0;
+
/* save original event record */
saved_size = snd_seq_event_packet_size(event);
memcpy(&event_saved, event, saved_size);
@@ -761,6 +781,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client,
read_unlock(&grp->list_lock);
else
up_read(&grp->list_mutex);
+ snd_seq_port_unlock(src_port);
memcpy(event, &event_saved, saved_size);
return (result < 0) ? result : num_ev;
}
@@ -769,25 +790,32 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
struct snd_seq_event *event,
int atomic, int hop)
{
- struct snd_seq_client_port *src_port;
- int ret = 0, ret2;
-
- src_port = snd_seq_port_use_ptr(client, event->source.port);
- if (src_port) {
- ret = __deliver_to_subscribers(client, event, src_port, atomic, hop);
- snd_seq_port_unlock(src_port);
- }
-
- if (client->ump_endpoint_port < 0 ||
- event->source.port == client->ump_endpoint_port)
- return ret;
+ int ret;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ int ret2;
+#endif
- src_port = snd_seq_port_use_ptr(client, client->ump_endpoint_port);
- if (!src_port)
+ ret = __deliver_to_subscribers(client, event,
+ event->source.port, atomic, hop);
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ if (!snd_seq_client_is_ump(client) || client->ump_endpoint_port < 0)
return ret;
- ret2 = __deliver_to_subscribers(client, event, src_port, atomic, hop);
- snd_seq_port_unlock(src_port);
- return ret2 < 0 ? ret2 : ret;
+ /* If it's an event from EP port (and with a UMP group),
+ * deliver to subscribers of the corresponding UMP group port, too.
+ * Or, if it's from non-EP port, deliver to subscribers of EP port, too.
+ */
+ if (event->source.port == client->ump_endpoint_port)
+ ret2 = __deliver_to_subscribers(client, event,
+ snd_seq_ump_group_port(event),
+ atomic, hop);
+ else
+ ret2 = __deliver_to_subscribers(client, event,
+ client->ump_endpoint_port,
+ atomic, hop);
+ if (ret2 < 0)
+ return ret2;
+#endif
+ return ret;
}
/* deliver an event to the destination port(s).
@@ -1136,8 +1164,7 @@ static __poll_t snd_seq_poll(struct file *file, poll_table * wait)
if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) {
/* check if data is available in the pool */
- if (!snd_seq_write_pool_allocated(client) ||
- snd_seq_pool_poll_wait(client->pool, file, wait))
+ if (snd_seq_pool_poll_wait(client->pool, file, wait))
mask |= EPOLLOUT | EPOLLWRNORM;
}
@@ -1195,7 +1222,7 @@ static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg)
int err = 0;
/* requested client number */
- cptr = snd_seq_client_use_ptr(info->client);
+ cptr = client_load_and_use_ptr(info->client);
if (cptr == NULL)
return -ENOENT; /* don't change !!! */
@@ -1257,7 +1284,7 @@ static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client,
struct snd_seq_client *cptr;
/* requested client number */
- cptr = snd_seq_client_use_ptr(client_info->client);
+ cptr = client_load_and_use_ptr(client_info->client);
if (cptr == NULL)
return -ENOENT; /* don't change !!! */
@@ -1392,7 +1419,7 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg)
struct snd_seq_client *cptr;
struct snd_seq_client_port *port;
- cptr = snd_seq_client_use_ptr(info->addr.client);
+ cptr = client_load_and_use_ptr(info->addr.client);
if (cptr == NULL)
return -ENXIO;
@@ -1496,10 +1523,10 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
struct snd_seq_client *receiver = NULL, *sender = NULL;
struct snd_seq_client_port *sport = NULL, *dport = NULL;
- receiver = snd_seq_client_use_ptr(subs->dest.client);
+ receiver = client_load_and_use_ptr(subs->dest.client);
if (!receiver)
goto __end;
- sender = snd_seq_client_use_ptr(subs->sender.client);
+ sender = client_load_and_use_ptr(subs->sender.client);
if (!sender)
goto __end;
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
@@ -1864,7 +1891,7 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
struct snd_seq_client_pool *info = arg;
struct snd_seq_client *cptr;
- cptr = snd_seq_client_use_ptr(info->client);
+ cptr = client_load_and_use_ptr(info->client);
if (cptr == NULL)
return -ENOENT;
memset(info, 0, sizeof(*info));
@@ -1968,7 +1995,7 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
struct snd_seq_client_port *sport = NULL;
result = -EINVAL;
- sender = snd_seq_client_use_ptr(subs->sender.client);
+ sender = client_load_and_use_ptr(subs->sender.client);
if (!sender)
goto __end;
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
@@ -1999,7 +2026,7 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
struct list_head *p;
int i;
- cptr = snd_seq_client_use_ptr(subs->root.client);
+ cptr = client_load_and_use_ptr(subs->root.client);
if (!cptr)
goto __end;
port = snd_seq_port_use_ptr(cptr, subs->root.port);
@@ -2066,7 +2093,7 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,
if (info->client < 0)
info->client = 0;
for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) {
- cptr = snd_seq_client_use_ptr(info->client);
+ cptr = client_load_and_use_ptr(info->client);
if (cptr)
break; /* found */
}
@@ -2089,7 +2116,7 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,
struct snd_seq_client *cptr;
struct snd_seq_client_port *port = NULL;
- cptr = snd_seq_client_use_ptr(info->addr.client);
+ cptr = client_load_and_use_ptr(info->addr.client);
if (cptr == NULL)
return -ENXIO;
@@ -2186,7 +2213,7 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller,
size = sizeof(struct snd_ump_endpoint_info);
else
size = sizeof(struct snd_ump_block_info);
- cptr = snd_seq_client_use_ptr(client);
+ cptr = client_load_and_use_ptr(client);
if (!cptr)
return -ENOENT;
@@ -2458,7 +2485,7 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
if (check_event_type_and_length(ev))
return -EINVAL;
- cptr = snd_seq_client_use_ptr(client);
+ cptr = client_load_and_use_ptr(client);
if (cptr == NULL)
return -EINVAL;
@@ -2555,8 +2582,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
if (client == NULL)
return -ENXIO;
- if (! snd_seq_write_pool_allocated(client))
- return 1;
if (snd_seq_pool_poll_wait(client->pool, file, wait))
return 1;
return 0;
@@ -2690,7 +2715,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
/* list the client table */
for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) {
- client = snd_seq_client_use_ptr(c);
+ client = client_load_and_use_ptr(c);
if (client == NULL)
continue;
if (client->type == NO_CLIENT) {
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 20155e3e87c6..ccde0ca3d208 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -427,6 +427,7 @@ int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file,
poll_table *wait)
{
poll_wait(file, &pool->output_sleep, wait);
+ guard(spinlock_irq)(&pool->lock);
return snd_seq_output_ok(pool);
}
diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c
index ff7e558b4d51..db2f169cae11 100644
--- a/sound/core/seq/seq_ump_convert.c
+++ b/sound/core/seq/seq_ump_convert.c
@@ -1285,3 +1285,21 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source,
else
return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop);
}
+
+/* return the UMP group-port number of the event;
+ * return -1 if groupless or non-UMP event
+ */
+int snd_seq_ump_group_port(const struct snd_seq_event *event)
+{
+ const struct snd_seq_ump_event *ump_ev =
+ (const struct snd_seq_ump_event *)event;
+ unsigned char type;
+
+ if (!snd_seq_ev_is_ump(event))
+ return -1;
+ type = ump_message_type(ump_ev->ump[0]);
+ if (ump_is_groupless_msg(type))
+ return -1;
+ /* group-port number starts from 1 */
+ return ump_message_group(ump_ev->ump[0]) + 1;
+}
diff --git a/sound/core/seq/seq_ump_convert.h b/sound/core/seq/seq_ump_convert.h
index 6c146d803280..4abf0a7637d7 100644
--- a/sound/core/seq/seq_ump_convert.h
+++ b/sound/core/seq/seq_ump_convert.h
@@ -18,5 +18,6 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source,
struct snd_seq_client_port *dest_port,
struct snd_seq_event *event,
int atomic, int hop);
+int snd_seq_ump_group_port(const struct snd_seq_event *event);
#endif /* __SEQ_UMP_CONVERT_H */
diff --git a/sound/core/seq_device.c b/sound/core/seq_device.c
index 4492be5d2317..bac9f8603734 100644
--- a/sound/core/seq_device.c
+++ b/sound/core/seq_device.c
@@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
static int snd_seq_bus_match(struct device *dev, const struct device_driver *drv)
{
struct snd_seq_device *sdev = to_seq_dev(dev);
- struct snd_seq_driver *sdrv = to_seq_drv(drv);
+ const struct snd_seq_driver *sdrv = to_seq_drv(drv);
return strcmp(sdrv->id, sdev->id) == 0 &&
sdrv->argsize == sdev->argsize;
diff --git a/sound/core/timer.c b/sound/core/timer.c
index fbada79380f9..d774b9b71ce2 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1515,91 +1515,97 @@ static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *ti
id->subdevice = timer->tmr_subdevice;
}
-static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
+static void get_next_device(struct snd_timer_id *id)
{
- struct snd_timer_id id;
struct snd_timer *timer;
struct list_head *p;
- if (copy_from_user(&id, _tid, sizeof(id)))
- return -EFAULT;
- guard(mutex)(&register_mutex);
- if (id.dev_class < 0) { /* first item */
+ if (id->dev_class < 0) { /* first item */
if (list_empty(&snd_timer_list))
- snd_timer_user_zero_id(&id);
+ snd_timer_user_zero_id(id);
else {
timer = list_entry(snd_timer_list.next,
struct snd_timer, device_list);
- snd_timer_user_copy_id(&id, timer);
+ snd_timer_user_copy_id(id, timer);
}
} else {
- switch (id.dev_class) {
+ switch (id->dev_class) {
case SNDRV_TIMER_CLASS_GLOBAL:
- id.device = id.device < 0 ? 0 : id.device + 1;
+ id->device = id->device < 0 ? 0 : id->device + 1;
list_for_each(p, &snd_timer_list) {
timer = list_entry(p, struct snd_timer, device_list);
if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) {
- snd_timer_user_copy_id(&id, timer);
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->tmr_device >= id.device) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->tmr_device >= id->device) {
+ snd_timer_user_copy_id(id, timer);
break;
}
}
if (p == &snd_timer_list)
- snd_timer_user_zero_id(&id);
+ snd_timer_user_zero_id(id);
break;
case SNDRV_TIMER_CLASS_CARD:
case SNDRV_TIMER_CLASS_PCM:
- if (id.card < 0) {
- id.card = 0;
+ if (id->card < 0) {
+ id->card = 0;
} else {
- if (id.device < 0) {
- id.device = 0;
+ if (id->device < 0) {
+ id->device = 0;
} else {
- if (id.subdevice < 0)
- id.subdevice = 0;
- else if (id.subdevice < INT_MAX)
- id.subdevice++;
+ if (id->subdevice < 0)
+ id->subdevice = 0;
+ else if (id->subdevice < INT_MAX)
+ id->subdevice++;
}
}
list_for_each(p, &snd_timer_list) {
timer = list_entry(p, struct snd_timer, device_list);
- if (timer->tmr_class > id.dev_class) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->tmr_class > id->dev_class) {
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->tmr_class < id.dev_class)
+ if (timer->tmr_class < id->dev_class)
continue;
- if (timer->card->number > id.card) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->card->number > id->card) {
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->card->number < id.card)
+ if (timer->card->number < id->card)
continue;
- if (timer->tmr_device > id.device) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->tmr_device > id->device) {
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->tmr_device < id.device)
+ if (timer->tmr_device < id->device)
continue;
- if (timer->tmr_subdevice > id.subdevice) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->tmr_subdevice > id->subdevice) {
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->tmr_subdevice < id.subdevice)
+ if (timer->tmr_subdevice < id->subdevice)
continue;
- snd_timer_user_copy_id(&id, timer);
+ snd_timer_user_copy_id(id, timer);
break;
}
if (p == &snd_timer_list)
- snd_timer_user_zero_id(&id);
+ snd_timer_user_zero_id(id);
break;
default:
- snd_timer_user_zero_id(&id);
+ snd_timer_user_zero_id(id);
}
}
+}
+
+static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
+{
+ struct snd_timer_id id;
+
+ if (copy_from_user(&id, _tid, sizeof(id)))
+ return -EFAULT;
+ scoped_guard(mutex, &register_mutex)
+ get_next_device(&id);
if (copy_to_user(_tid, &id, sizeof(*_tid)))
return -EFAULT;
return 0;
@@ -1620,23 +1626,24 @@ static int snd_timer_user_ginfo(struct file *file,
tid = ginfo->tid;
memset(ginfo, 0, sizeof(*ginfo));
ginfo->tid = tid;
- guard(mutex)(&register_mutex);
- t = snd_timer_find(&tid);
- if (!t)
- return -ENODEV;
- ginfo->card = t->card ? t->card->number : -1;
- if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
- ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
- strscpy(ginfo->id, t->id, sizeof(ginfo->id));
- strscpy(ginfo->name, t->name, sizeof(ginfo->name));
- scoped_guard(spinlock_irq, &t->lock)
- ginfo->resolution = snd_timer_hw_resolution(t);
- if (t->hw.resolution_min > 0) {
- ginfo->resolution_min = t->hw.resolution_min;
- ginfo->resolution_max = t->hw.resolution_max;
- }
- list_for_each(p, &t->open_list_head) {
- ginfo->clients++;
+ scoped_guard(mutex, &register_mutex) {
+ t = snd_timer_find(&tid);
+ if (!t)
+ return -ENODEV;
+ ginfo->card = t->card ? t->card->number : -1;
+ if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
+ ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
+ strscpy(ginfo->id, t->id, sizeof(ginfo->id));
+ strscpy(ginfo->name, t->name, sizeof(ginfo->name));
+ scoped_guard(spinlock_irq, &t->lock)
+ ginfo->resolution = snd_timer_hw_resolution(t);
+ if (t->hw.resolution_min > 0) {
+ ginfo->resolution_min = t->hw.resolution_min;
+ ginfo->resolution_max = t->hw.resolution_max;
+ }
+ list_for_each(p, &t->open_list_head) {
+ ginfo->clients++;
+ }
}
if (copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
return -EFAULT;
@@ -1674,31 +1681,31 @@ static int snd_timer_user_gstatus(struct file *file,
struct snd_timer_gstatus gstatus;
struct snd_timer_id tid;
struct snd_timer *t;
- int err = 0;
if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus)))
return -EFAULT;
tid = gstatus.tid;
memset(&gstatus, 0, sizeof(gstatus));
gstatus.tid = tid;
- guard(mutex)(&register_mutex);
- t = snd_timer_find(&tid);
- if (t != NULL) {
- guard(spinlock_irq)(&t->lock);
- gstatus.resolution = snd_timer_hw_resolution(t);
- if (t->hw.precise_resolution) {
- t->hw.precise_resolution(t, &gstatus.resolution_num,
- &gstatus.resolution_den);
+ scoped_guard(mutex, &register_mutex) {
+ t = snd_timer_find(&tid);
+ if (t != NULL) {
+ guard(spinlock_irq)(&t->lock);
+ gstatus.resolution = snd_timer_hw_resolution(t);
+ if (t->hw.precise_resolution) {
+ t->hw.precise_resolution(t, &gstatus.resolution_num,
+ &gstatus.resolution_den);
+ } else {
+ gstatus.resolution_num = gstatus.resolution;
+ gstatus.resolution_den = 1000000000uL;
+ }
} else {
- gstatus.resolution_num = gstatus.resolution;
- gstatus.resolution_den = 1000000000uL;
+ return -ENODEV;
}
- } else {
- err = -ENODEV;
}
- if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
- err = -EFAULT;
- return err;
+ if (copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
+ return -EFAULT;
+ return 0;
}
static int snd_timer_user_tselect(struct file *file,
diff --git a/sound/hda/hda_bus_type.c b/sound/hda/hda_bus_type.c
index 7545ace7b0ee..eb72a7af2e56 100644
--- a/sound/hda/hda_bus_type.c
+++ b/sound/hda/hda_bus_type.c
@@ -21,7 +21,7 @@ MODULE_LICENSE("GPL");
* driver id_table and returns the matching device id entry.
*/
const struct hda_device_id *
-hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv)
+hdac_get_device_id(struct hdac_device *hdev, const struct hdac_driver *drv)
{
if (drv->id_table) {
const struct hda_device_id *id = drv->id_table;
@@ -38,7 +38,7 @@ hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv)
}
EXPORT_SYMBOL_GPL(hdac_get_device_id);
-static int hdac_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
+static int hdac_codec_match(struct hdac_device *dev, const struct hdac_driver *drv)
{
if (hdac_get_device_id(dev, drv))
return 1;
@@ -49,7 +49,7 @@ static int hdac_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
static int hda_bus_match(struct device *dev, const struct device_driver *drv)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
- struct hdac_driver *hdrv = drv_to_hdac_driver(drv);
+ const struct hdac_driver *hdrv = drv_to_hdac_driver(drv);
if (hdev->type != hdrv->type)
return 0;
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index 9f849e05ce79..34825b2f3b10 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -539,6 +539,11 @@ static const struct config_entry config_table[] = {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
.device = PCI_DEVICE_ID_INTEL_HDA_PTL,
},
+ {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = PCI_DEVICE_ID_INTEL_HDA_PTL_H,
+ },
+
#endif
};
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 99006dc4777e..5c9e2d41d900 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -98,7 +98,7 @@ static int snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card,
pdev = pnp_request_card_device(card, id->devs[1].id, NULL);
if (pdev == NULL) {
mpu_port[dev] = -1;
- dev_warn(&pdev->dev, "MPU401 device busy, skipping.\n");
+ pr_warn("MPU401 device busy, skipping.\n");
return 0;
}
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index 74db11525003..5a083eecaa6b 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -703,6 +703,9 @@ static int snd_sb16_dma_control_put(struct snd_kcontrol *kcontrol, struct snd_ct
unsigned char nval, oval;
int change;
+ if (chip->mode & (SB_MODE_PLAYBACK | SB_MODE_CAPTURE))
+ return -EBUSY;
+
nval = ucontrol->value.enumerated.item[0];
if (nval > 2)
return -EINVAL;
@@ -711,6 +714,10 @@ static int snd_sb16_dma_control_put(struct snd_kcontrol *kcontrol, struct snd_ct
change = nval != oval;
snd_sb16_set_dma_mode(chip, nval);
spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (change) {
+ snd_dma_disable(chip->dma8);
+ snd_dma_disable(chip->dma16);
+ }
return change;
}
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index c6c018b40c69..4e0693f0ab0f 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -1561,7 +1561,7 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct es1968 *chip = snd_pcm_substream_chip(substream);
struct esschan *es;
- int apu1, apu2;
+ int err, apu1, apu2;
apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE);
if (apu1 < 0)
@@ -1605,7 +1605,9 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream)
runtime->hw = snd_es1968_capture;
runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max =
calc_available_memory_size(chip) - 1024; /* keep MIXBUF size */
- snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
+ err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
+ if (err < 0)
+ return err;
spin_lock_irq(&chip->substream_lock);
list_add(&es->list, &chip->substream_list);
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 68f1eee9e5c9..fd9391e61b3d 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -96,9 +96,7 @@ config SND_HDA_CIRRUS_SCODEC
config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS
- select SND_HDA_CIRRUS_SCODEC
- select GPIOLIB
- depends on KUNIT
+ depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT
default KUNIT_ALL_TESTS
help
This builds KUnit tests for the cirrus side-codec library.
@@ -208,6 +206,7 @@ comment "Set to Y if you want auto-loading the side codec driver"
config SND_HDA_CODEC_REALTEK
tristate "Build Realtek HD-audio codec support"
+ depends on INPUT
select SND_HDA_GENERIC
select SND_HDA_GENERIC_LEDS
select SND_HDA_SCODEC_COMPONENT
diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
index 61d2314834e7..d8249d997c2a 100644
--- a/sound/pci/hda/cs35l41_hda_property.c
+++ b/sound/pci/hda/cs35l41_hda_property.c
@@ -31,6 +31,9 @@ struct cs35l41_config {
};
static const struct cs35l41_config cs35l41_config_table[] = {
+ { "10251826", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "1025182C", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "10251844", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "10280B27", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10280B28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10280BEB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
@@ -452,6 +455,9 @@ struct cs35l41_prop_model {
static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
{ "CLSA0100", NULL, lenovo_legion_no_acpi },
{ "CLSA0101", NULL, lenovo_legion_no_acpi },
+ { "CSC3551", "10251826", generic_dsd_config },
+ { "CSC3551", "1025182C", generic_dsd_config },
+ { "CSC3551", "10251844", generic_dsd_config },
{ "CSC3551", "10280B27", generic_dsd_config },
{ "CSC3551", "10280B28", generic_dsd_config },
{ "CSC3551", "10280BEB", generic_dsd_config },
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index e51d47572557..13a7d92e8d8d 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -31,8 +31,9 @@ static void generate_tone(struct hda_beep *beep, int tone)
beep->power_hook(beep, true);
beep->playing = 1;
}
- snd_hda_codec_write(codec, beep->nid, 0,
- AC_VERB_SET_BEEP_CONTROL, tone);
+ if (!codec->beep_just_power_on)
+ snd_hda_codec_write(codec, beep->nid, 0,
+ AC_VERB_SET_BEEP_CONTROL, tone);
if (!tone && beep->playing) {
beep->playing = 0;
if (beep->power_hook)
@@ -212,10 +213,12 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
struct hda_beep *beep;
int err;
- if (!snd_hda_get_bool_hint(codec, "beep"))
- return 0; /* disabled explicitly by hints */
- if (codec->beep_mode == HDA_BEEP_MODE_OFF)
- return 0; /* disabled by module option */
+ if (!codec->beep_just_power_on) {
+ if (!snd_hda_get_bool_hint(codec, "beep"))
+ return 0; /* disabled explicitly by hints */
+ if (codec->beep_mode == HDA_BEEP_MODE_OFF)
+ return 0; /* disabled by module option */
+ }
beep = kzalloc(sizeof(*beep), GFP_KERNEL);
if (beep == NULL)
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
index b7ca2a83fbb0..f8f1b1f6b138 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/pci/hda/hda_bind.c
@@ -18,10 +18,10 @@
/*
* find a matching codec id
*/
-static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
+static int hda_codec_match(struct hdac_device *dev, const struct hdac_driver *drv)
{
struct hda_codec *codec = container_of(dev, struct hda_codec, core);
- struct hda_codec_driver *driver =
+ const struct hda_codec_driver *driver =
container_of(drv, struct hda_codec_driver, core);
const struct hda_device_id *list;
/* check probe_id instead of vendor_id if set */
@@ -44,7 +44,7 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
struct hda_codec *codec = container_of(dev, struct hda_codec, core);
/* ignore unsol events during shutdown */
- if (codec->bus->shutdown)
+ if (codec->card->shutdown || codec->bus->shutdown)
return;
/* ignore unsol events during system suspend/resume */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index b4540c5cd2a6..d4e325b78533 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -37,6 +37,7 @@
#include <linux/completion.h>
#include <linux/acpi.h>
#include <linux/pgtable.h>
+#include <linux/dmi.h>
#ifdef CONFIG_X86
/* for snoop control */
@@ -1360,8 +1361,21 @@ static void azx_free(struct azx *chip)
if (use_vga_switcheroo(hda)) {
if (chip->disabled && hda->probe_continued)
snd_hda_unlock_devices(&chip->bus);
- if (hda->vga_switcheroo_registered)
+ if (hda->vga_switcheroo_registered) {
vga_switcheroo_unregister_client(chip->pci);
+
+ /* Some GPUs don't have sound, and azx_first_init fails,
+ * leaving the device probed but non-functional. As long
+ * as it's probed, the PCI subsystem keeps its runtime
+ * PM status as active. Force it to suspended (as we
+ * actually stop the chip) to allow GPU to suspend via
+ * vga_switcheroo, and print a warning.
+ */
+ dev_warn(&pci->dev, "GPU sound probed, but not operational: please add a quirk to driver_denylist\n");
+ pm_runtime_disable(&pci->dev);
+ pm_runtime_set_suspended(&pci->dev);
+ pm_runtime_enable(&pci->dev);
+ }
}
if (bus->chip_init) {
@@ -2071,6 +2085,27 @@ static const struct pci_device_id driver_denylist[] = {
{}
};
+static struct pci_device_id driver_denylist_ideapad_z570[] = {
+ { PCI_DEVICE_SUB(0x10de, 0x0bea, 0x0000, 0x0000) }, /* NVIDIA GF108 HDA */
+ {}
+};
+
+/* DMI-based denylist, to be used when:
+ * - PCI subsystem IDs are zero, impossible to distinguish from valid sound cards.
+ * - Different modifications of the same laptop use different GPU models.
+ */
+static const struct dmi_system_id driver_denylist_dmi[] = {
+ {
+ /* No HDA in NVIDIA DGPU. BIOS disables it, but quirk_nvidia_hda() reenables. */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"),
+ },
+ .driver_data = &driver_denylist_ideapad_z570,
+ },
+ {}
+};
+
static const struct hda_controller_ops pci_hda_ops = {
.disable_msi_reset_irq = disable_msi_reset_irq,
.position_check = azx_position_check,
@@ -2081,6 +2116,7 @@ static DECLARE_BITMAP(probed_devs, SNDRV_CARDS);
static int azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
+ const struct dmi_system_id *dmi;
struct snd_card *card;
struct hda_intel *hda;
struct azx *chip;
@@ -2093,6 +2129,12 @@ static int azx_probe(struct pci_dev *pci,
return -ENODEV;
}
+ dmi = dmi_first_match(driver_denylist_dmi);
+ if (dmi && pci_match_id(dmi->driver_data, pci)) {
+ dev_info(&pci->dev, "Skipping the device on the DMI denylist\n");
+ return -ENODEV;
+ }
+
dev = find_first_zero_bit(probed_devs, SNDRV_CARDS);
if (dev >= SNDRV_CARDS)
return -ENODEV;
@@ -2242,6 +2284,10 @@ static const struct snd_pci_quirk power_save_denylist[] = {
SND_PCI_QUIRK(0x1631, 0xe017, "Packard Bell NEC IMEDIA 5204", 0),
/* KONTRON SinglePC may cause a stall at runtime resume */
SND_PCI_QUIRK(0x1734, 0x1232, "KONTRON SinglePC", 0),
+ /* Dell ALC3271 */
+ SND_PCI_QUIRK(0x1028, 0x0962, "Dell ALC3271", 0),
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=220210 */
+ SND_PCI_QUIRK(0x17aa, 0x5079, "Lenovo Thinkpad E15", 0),
{}
};
@@ -2506,6 +2552,8 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_ARL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Panther Lake */
{ PCI_DEVICE_DATA(INTEL, HDA_PTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
+ /* Panther Lake-H */
+ { PCI_DEVICE_DATA(INTEL, HDA_PTL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
/* Apollolake (Broxton-P) */
{ PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
/* Gemini-Lake */
@@ -2679,6 +2727,9 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_VDEVICE(ATI, 0xab38),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
+ { PCI_VDEVICE(ATI, 0xab40),
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
+ AZX_DCAPS_PM_RUNTIME },
/* GLENFLY */
{ PCI_DEVICE(PCI_VENDOR_ID_GLENFLY, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index d967e70a7058..12a144a269ee 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -72,6 +72,10 @@
struct hda_tegra_soc {
bool has_hda2codec_2x_reset;
bool has_hda2hdmi;
+ bool has_hda2codec_2x;
+ bool input_stream;
+ bool always_on;
+ bool requires_init;
};
struct hda_tegra {
@@ -187,7 +191,9 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
if (rc != 0)
return rc;
if (chip->running) {
- hda_tegra_init(hda);
+ if (hda->soc->requires_init)
+ hda_tegra_init(hda);
+
azx_init_chip(chip, 1);
/* disable controller wake up event*/
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
@@ -252,7 +258,8 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
bus->remap_addr = hda->regs + HDA_BAR0;
bus->addr = res->start + HDA_BAR0;
- hda_tegra_init(hda);
+ if (hda->soc->requires_init)
+ hda_tegra_init(hda);
return 0;
}
@@ -325,7 +332,7 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
* starts with offset 0 which is wrong as HW register for output stream
* offset starts with 4.
*/
- if (of_device_is_compatible(np, "nvidia,tegra234-hda"))
+ if (!hda->soc->input_stream)
chip->capture_streams = 4;
chip->playback_streams = (gcap >> 12) & 0x0f;
@@ -421,7 +428,6 @@ static int hda_tegra_create(struct snd_card *card,
chip->driver_caps = driver_caps;
chip->driver_type = driver_caps & 0xff;
chip->dev_index = 0;
- chip->jackpoll_interval = msecs_to_jiffies(5000);
INIT_LIST_HEAD(&chip->pcm_list);
chip->codec_probe_mask = -1;
@@ -438,7 +444,16 @@ static int hda_tegra_create(struct snd_card *card,
chip->bus.core.sync_write = 0;
chip->bus.core.needs_damn_long_delay = 1;
chip->bus.core.aligned_mmio = 1;
- chip->bus.jackpoll_in_suspend = 1;
+
+ /*
+ * HDA power domain and clocks are always on for Tegra264 and
+ * the jack detection logic would work always, so no need of
+ * jack polling mechanism running.
+ */
+ if (!hda->soc->always_on) {
+ chip->jackpoll_interval = msecs_to_jiffies(5000);
+ chip->bus.jackpoll_in_suspend = 1;
+ }
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) {
@@ -452,22 +467,44 @@ static int hda_tegra_create(struct snd_card *card,
static const struct hda_tegra_soc tegra30_data = {
.has_hda2codec_2x_reset = true,
.has_hda2hdmi = true,
+ .has_hda2codec_2x = true,
+ .input_stream = true,
+ .always_on = false,
+ .requires_init = true,
};
static const struct hda_tegra_soc tegra194_data = {
.has_hda2codec_2x_reset = false,
.has_hda2hdmi = true,
+ .has_hda2codec_2x = true,
+ .input_stream = true,
+ .always_on = false,
+ .requires_init = true,
};
static const struct hda_tegra_soc tegra234_data = {
.has_hda2codec_2x_reset = true,
.has_hda2hdmi = false,
+ .has_hda2codec_2x = true,
+ .input_stream = false,
+ .always_on = false,
+ .requires_init = true,
+};
+
+static const struct hda_tegra_soc tegra264_data = {
+ .has_hda2codec_2x_reset = true,
+ .has_hda2hdmi = false,
+ .has_hda2codec_2x = false,
+ .input_stream = false,
+ .always_on = true,
+ .requires_init = false,
};
static const struct of_device_id hda_tegra_match[] = {
{ .compatible = "nvidia,tegra30-hda", .data = &tegra30_data },
{ .compatible = "nvidia,tegra194-hda", .data = &tegra194_data },
{ .compatible = "nvidia,tegra234-hda", .data = &tegra234_data },
+ { .compatible = "nvidia,tegra264-hda", .data = &tegra264_data },
{},
};
MODULE_DEVICE_TABLE(of, hda_tegra_match);
@@ -522,7 +559,9 @@ static int hda_tegra_probe(struct platform_device *pdev)
hda->clocks[hda->nclocks++].id = "hda";
if (hda->soc->has_hda2hdmi)
hda->clocks[hda->nclocks++].id = "hda2hdmi";
- hda->clocks[hda->nclocks++].id = "hda2codec_2x";
+
+ if (hda->soc->has_hda2codec_2x)
+ hda->clocks[hda->nclocks++].id = "hda2codec_2x";
err = devm_clk_bulk_get(&pdev->dev, hda->nclocks, hda->clocks);
if (err < 0)
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 643e0496b093..b05ef4bec660 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -4551,6 +4551,9 @@ HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP", patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP", patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP", patch_tegra234_hdmi),
HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi),
@@ -4589,15 +4592,32 @@ HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch),
HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch),
HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP", patch_gf_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4a3b4c6d4114..085f0697bff1 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -28,6 +28,7 @@
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
+#include "hda_beep.h"
#include "hda_jack.h"
#include "hda_generic.h"
#include "hda_component.h"
@@ -440,6 +441,10 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
fallthrough;
case 0x10ec0215:
+ case 0x10ec0236:
+ case 0x10ec0245:
+ case 0x10ec0256:
+ case 0x10ec0257:
case 0x10ec0285:
case 0x10ec0289:
alc_update_coef_idx(codec, 0x36, 1<<13, 0);
@@ -447,12 +452,8 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
case 0x10ec0230:
case 0x10ec0233:
case 0x10ec0235:
- case 0x10ec0236:
- case 0x10ec0245:
case 0x10ec0255:
- case 0x10ec0256:
case 0x19e58326:
- case 0x10ec0257:
case 0x10ec0282:
case 0x10ec0283:
case 0x10ec0286:
@@ -586,6 +587,9 @@ static void alc_shutup_pins(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ if (spec->no_shutup_pins)
+ return;
+
switch (codec->core.vendor_id) {
case 0x10ec0236:
case 0x10ec0256:
@@ -601,8 +605,7 @@ static void alc_shutup_pins(struct hda_codec *codec)
alc_headset_mic_no_shutup(codec);
break;
default:
- if (!spec->no_shutup_pins)
- snd_hda_shutup_pins(codec);
+ snd_hda_shutup_pins(codec);
break;
}
}
@@ -2655,6 +2658,7 @@ static const struct hda_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
@@ -3845,6 +3849,79 @@ static void alc225_shutup(struct hda_codec *codec)
}
}
+static void alc222_init(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t hp_pin = alc_get_hp_pin(spec);
+ bool hp1_pin_sense, hp2_pin_sense;
+
+ if (!hp_pin)
+ return;
+
+ msleep(30);
+
+ hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+ hp2_pin_sense = snd_hda_jack_detect(codec, 0x14);
+
+ if (hp1_pin_sense || hp2_pin_sense) {
+ msleep(2);
+
+ if (hp1_pin_sense)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ if (hp2_pin_sense)
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ msleep(75);
+
+ if (hp1_pin_sense)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ if (hp2_pin_sense)
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+ msleep(75);
+ }
+}
+
+static void alc222_shutup(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t hp_pin = alc_get_hp_pin(spec);
+ bool hp1_pin_sense, hp2_pin_sense;
+
+ if (!hp_pin)
+ hp_pin = 0x21;
+
+ hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+ hp2_pin_sense = snd_hda_jack_detect(codec, 0x14);
+
+ if (hp1_pin_sense || hp2_pin_sense) {
+ msleep(2);
+
+ if (hp1_pin_sense)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ if (hp2_pin_sense)
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+ msleep(75);
+
+ if (hp1_pin_sense)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ if (hp2_pin_sense)
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+ msleep(75);
+ }
+ alc_auto_setup_eapd(codec, false);
+ alc_shutup_pins(codec);
+}
+
static void alc_default_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -4669,6 +4746,22 @@ static void alc245_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
}
}
+static void alc245_fixup_hp_mute_led_v1_coefbit(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->mute_led_polarity = 0;
+ spec->mute_led_coef.idx = 0x0b;
+ spec->mute_led_coef.mask = 3 << 2;
+ spec->mute_led_coef.on = 1 << 3;
+ spec->mute_led_coef.off = 0;
+ snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+ }
+}
+
/* turn on/off mic-mute LED per capture hook by coef bit */
static int coef_micmute_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
@@ -4719,6 +4812,21 @@ static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
}
}
+static void alc295_fixup_hp_mute_led_coefbit11(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->mute_led_polarity = 0;
+ spec->mute_led_coef.idx = 0xb;
+ spec->mute_led_coef.mask = 3 << 3;
+ spec->mute_led_coef.on = 1 << 3;
+ spec->mute_led_coef.off = 1 << 4;
+ snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+ }
+}
+
static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -4929,7 +5037,6 @@ static void alc298_fixup_samsung_amp_v2_4_amps(struct hda_codec *codec,
alc298_samsung_v2_init_amps(codec, 4);
}
-#if IS_REACHABLE(CONFIG_INPUT)
static void gpio2_mic_hotkey_event(struct hda_codec *codec,
struct hda_jack_callback *event)
{
@@ -5038,10 +5145,6 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
spec->kb_dev = NULL;
}
}
-#else /* INPUT */
-#define alc280_fixup_hp_gpio2_mic_hotkey NULL
-#define alc233_fixup_lenovo_line2_mic_hotkey NULL
-#endif /* INPUT */
static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -5055,6 +5158,16 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
}
}
+static void alc233_fixup_lenovo_low_en_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->micmute_led_polarity = 1;
+ alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action);
+}
+
static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
{
if (delay <= 0)
@@ -6492,6 +6605,17 @@ static void alc285_fixup_speaker2_to_dac1(struct hda_codec *codec,
}
}
+/* disable DAC3 (0x06) selection on NID 0x15 - share Speaker/Bass Speaker DAC 0x03 */
+static void alc294_fixup_bass_speaker_15(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ static const hda_nid_t conn[] = { 0x02, 0x03 };
+ snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
+ snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+ }
+}
+
/* Hook to update amp GPIO4 for automute */
static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
struct hda_jack_callback *jack)
@@ -6691,7 +6815,10 @@ static void alc256_fixup_chromebook(struct hda_codec *codec,
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
- spec->gen.suppress_auto_mute = 1;
+ if (codec->core.subsystem_id == 0x10280d76)
+ spec->gen.suppress_auto_mute = 0;
+ else
+ spec->gen.suppress_auto_mute = 1;
spec->gen.suppress_auto_mic = 1;
spec->en_3kpull_low = false;
break;
@@ -6843,6 +6970,41 @@ static void alc285_fixup_hp_spectre_x360_eb1(struct hda_codec *codec,
}
}
+/* GPIO1 = amplifier on/off */
+static void alc285_fixup_hp_spectre_x360_df1(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const hda_nid_t conn[] = { 0x02 };
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x14, 0x90170110 }, /* front/high speakers */
+ { 0x17, 0x90170130 }, /* back/bass speakers */
+ { }
+ };
+
+ // enable mute led
+ alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* needed for amp of back speakers */
+ spec->gpio_mask |= 0x01;
+ spec->gpio_dir |= 0x01;
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ /* share DAC to have unified volume control */
+ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ /* need to toggle GPIO to enable the amp of back speakers */
+ alc_update_gpio_data(codec, 0x01, true);
+ msleep(100);
+ alc_update_gpio_data(codec, 0x01, false);
+ break;
+ }
+}
+
static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -6915,6 +7077,30 @@ static void alc285_fixup_hp_envy_x360(struct hda_codec *codec,
}
}
+static void alc285_fixup_hp_beep(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ codec->beep_just_power_on = true;
+ } else if (action == HDA_FIXUP_ACT_INIT) {
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+ /*
+ * Just enable loopback to internal speaker and headphone jack.
+ * Disable amplification to get about the same beep volume as
+ * was on pure BIOS setup before loading the driver.
+ */
+ alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13));
+
+ snd_hda_enable_beep_device(codec, 1);
+
+#if !IS_ENABLED(CONFIG_INPUT_PCSPKR)
+ dev_warn_once(hda_codec_dev(codec),
+ "enable CONFIG_INPUT_PCSPKR to get PC beeps\n");
+#endif
+#endif
+ }
+}
+
/* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
@@ -7432,6 +7618,24 @@ static void alc245_fixup_hp_spectre_x360_16_aa0xxx(struct hda_codec *codec,
alc245_fixup_hp_gpio_led(codec, fix, action);
}
+static void alc245_fixup_hp_zbook_firefly_g12a(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const hda_nid_t conn[] = { 0x02 };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.auto_mute_via_amp = 1;
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ }
+
+ cs35l41_fixup_i2c_two(codec, fix, action);
+ alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+ alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
/*
* ALC287 PCM hooks
*/
@@ -7476,6 +7680,16 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
}
+/*
+ * Clear COEF 0x0d (PCBEEP passthrough) bit 0x40 where BIOS sets it wrongly
+ * at PM resume
+ */
+static void alc283_fixup_dell_hp_resume(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_INIT)
+ alc_write_coef_idx(codec, 0xd, 0x2800);
+}
enum {
ALC269_FIXUP_GPIO2,
@@ -7546,6 +7760,7 @@ enum {
ALC290_FIXUP_MONO_SPEAKERS_HSJACK,
ALC290_FIXUP_SUBWOOFER,
ALC290_FIXUP_SUBWOOFER_HSJACK,
+ ALC295_FIXUP_HP_MUTE_LED_COEFBIT11,
ALC269_FIXUP_THINKPAD_ACPI,
ALC269_FIXUP_DMIC_THINKPAD_ACPI,
ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13,
@@ -7573,6 +7788,7 @@ enum {
ALC280_FIXUP_HP_9480M,
ALC245_FIXUP_HP_X360_AMP,
ALC285_FIXUP_HP_SPECTRE_X360_EB1,
+ ALC285_FIXUP_HP_SPECTRE_X360_DF1,
ALC285_FIXUP_HP_ENVY_X360,
ALC288_FIXUP_DELL_HEADSET_MODE,
ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
@@ -7588,6 +7804,7 @@ enum {
ALC275_FIXUP_DELL_XPS,
ALC293_FIXUP_LENOVO_SPK_NOISE,
ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
+ ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED,
ALC255_FIXUP_DELL_SPK_NOISE,
ALC225_FIXUP_DISABLE_MIC_VREF,
ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
@@ -7657,7 +7874,6 @@ enum {
ALC285_FIXUP_THINKPAD_X1_GEN7,
ALC285_FIXUP_THINKPAD_HEADSET_JACK,
ALC294_FIXUP_ASUS_ALLY,
- ALC294_FIXUP_ASUS_ALLY_X,
ALC294_FIXUP_ASUS_ALLY_PINS,
ALC294_FIXUP_ASUS_ALLY_VERBS,
ALC294_FIXUP_ASUS_ALLY_SPEAKER,
@@ -7674,6 +7890,7 @@ enum {
ALC285_FIXUP_HP_GPIO_LED,
ALC285_FIXUP_HP_MUTE_LED,
ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
+ ALC285_FIXUP_HP_BEEP_MICMUTE_LED,
ALC236_FIXUP_HP_MUTE_LED_COEFBIT2,
ALC236_FIXUP_HP_GPIO_LED,
ALC236_FIXUP_HP_MUTE_LED,
@@ -7755,6 +7972,7 @@ enum {
ALC287_FIXUP_TAS2781_I2C,
ALC287_FIXUP_YOGA7_14ARB7_I2C,
ALC245_FIXUP_HP_MUTE_LED_COEFBIT,
+ ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT,
ALC245_FIXUP_HP_X360_MUTE_LEDS,
ALC287_FIXUP_THINKPAD_I2S_SPK,
ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD,
@@ -7765,6 +7983,7 @@ enum {
ALC256_FIXUP_HEADPHONE_AMP_VOL,
ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX,
ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX,
+ ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A,
ALC285_FIXUP_ASUS_GA403U,
ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC,
ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1,
@@ -7775,6 +7994,9 @@ enum {
ALC245_FIXUP_CLEVO_NOISY_MIC,
ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
ALC233_FIXUP_MEDION_MTL_SPK,
+ ALC294_FIXUP_BASS_SPEAKER_15,
+ ALC283_FIXUP_DELL_HP_RESUME,
+ ALC294_FIXUP_ASUS_CS35L41_SPI_2,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -8574,6 +8796,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc233_fixup_lenovo_line2_mic_hotkey,
},
+ [ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc233_fixup_lenovo_low_en_micmute_led,
+ },
[ALC233_FIXUP_INTEL_NUC8_DMIC] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic,
@@ -9096,12 +9322,6 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
},
- [ALC294_FIXUP_ASUS_ALLY_X] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = tas2781_fixup_i2c,
- .chained = true,
- .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
- },
[ALC294_FIXUP_ASUS_ALLY_PINS] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -9261,6 +9481,12 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_hp_spectre_x360_mute_led,
},
+ [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_beep,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_HP_MUTE_LED,
+ },
[ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc236_fixup_hp_mute_led_coefbit2,
@@ -9283,6 +9509,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC283_FIXUP_INT_MIC,
},
+ [ALC295_FIXUP_HP_MUTE_LED_COEFBIT11] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc295_fixup_hp_mute_led_coefbit11,
+ },
[ALC298_FIXUP_SAMSUNG_AMP] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc298_fixup_samsung_amp,
@@ -9628,6 +9858,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_hp_spectre_x360_eb1
},
+ [ALC285_FIXUP_HP_SPECTRE_X360_DF1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_spectre_x360_df1
+ },
[ALC285_FIXUP_HP_ENVY_X360] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_hp_envy_x360,
@@ -9986,6 +10220,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc245_fixup_hp_mute_led_coefbit,
},
+ [ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_mute_led_v1_coefbit,
+ },
[ALC245_FIXUP_HP_X360_MUTE_LEDS] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc245_fixup_hp_mute_led_coefbit,
@@ -10034,6 +10272,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc245_fixup_hp_spectre_x360_16_aa0xxx,
},
+ [ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_zbook_firefly_g12a,
+ },
[ALC285_FIXUP_ASUS_GA403U] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_asus_ga403u,
@@ -10103,6 +10345,20 @@ static const struct hda_fixup alc269_fixups[] = {
{ }
},
},
+ [ALC294_FIXUP_BASS_SPEAKER_15] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc294_fixup_bass_speaker_15,
+ },
+ [ALC283_FIXUP_DELL_HP_RESUME] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc283_fixup_dell_hp_resume,
+ },
+ [ALC294_FIXUP_ASUS_CS35L41_SPI_2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_spi_two,
+ .chained = true,
+ .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC,
+ },
};
static const struct hda_quirk alc269_fixup_tbl[] = {
@@ -10163,6 +10419,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0604, "Dell Venue 11 Pro 7130", ALC283_FIXUP_DELL_HP_RESUME),
SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X),
@@ -10194,6 +10451,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB),
+ SND_PCI_QUIRK(0x1028, 0x0879, "Dell Latitude 5420 Rugged", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
@@ -10318,6 +10576,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360),
SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11),
SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360),
SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
@@ -10325,6 +10584,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+ SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1),
SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
@@ -10335,7 +10595,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT),
- SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED),
SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
@@ -10348,6 +10608,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x87cc, "HP Pavilion 15-eg0xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87d3, "HP Laptop 15-gw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x87df, "HP ProBook 430 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
@@ -10365,6 +10626,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8811, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x8812, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x881d, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x881e, "HP Laptop 15s-du3xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
@@ -10395,6 +10657,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8975, "HP EliteBook x360 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x897d, "HP mt440 Mobile Thin Client U74", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8981, "HP Elite Dragonfly G3", ALC245_FIXUP_CS35L41_SPI_4),
+ SND_PCI_QUIRK(0x103c, 0x898a, "HP Pavilion 15-eg100", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x898e, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x898f, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8991, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
@@ -10424,6 +10687,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a4f, "HP Victus 15-fa0xxx (MB 8A4F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
@@ -10469,6 +10733,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8bbe, "HP Victus 16-r0xxx (MB 8BBE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
@@ -10521,27 +10788,71 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c9c, "HP Victus 16-s1xxx (MB 8C9C)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8caf, "HP Elite mt645 G8 Mobile Thin Client", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8cbd, "HP Pavilion Aero Laptop 13-bg0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
- SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+ SND_PCI_QUIRK(0x103c, 0x8cde, "HP OmniBook Ultra Flip Laptop 14t", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
SND_PCI_QUIRK(0x103c, 0x8cdf, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ce0, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d85, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d86, "HP Elite X360 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d8c, "HP EliteBook 13 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d8d, "HP Elite X360 13 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d8e, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d8f, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
- SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
- SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
- SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8d9e, "HP 17 Turbine OmniBook X DIS", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8d9f, "HP 14 Cadet (x360)", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8da0, "HP 16 Clipper OmniBook 7(X360)", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8da1, "HP 16 Clipper OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8da7, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8da8, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8dec, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dee, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8df0, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dfe, "HP EliteBook 665 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e11, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e12, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e13, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e14, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e15, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e16, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e17, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e1b, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e1c, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e1d, "HP ZBook X Gli 16 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e2c, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e36, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e37, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e3a, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e3b, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
+ SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x1074, "ASUS G614PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK),
SND_PCI_QUIRK(0x1043, 0x10a4, "ASUS TP3407SA", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
@@ -10549,19 +10860,23 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x10d3, "ASUS K6500ZC", ALC294_FIXUP_ASUS_SPK),
SND_PCI_QUIRK(0x1043, 0x1154, "ASUS TP3607SH", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x1194, "ASUS UM3406KA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15),
SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1294, "ASUS B3405CVA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x12a3, "Asus N7691ZM", ALC269_FIXUP_ASUS_N7601ZM),
SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
- SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC),
- SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x12b4, "ASUS B3405CCA / P3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1460, "Asus VivoBook 15", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
@@ -10571,6 +10886,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601VV/VU/VJ/VQ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G614JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS G513PI/PU/PV", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x14f2, "ASUS VivoBook X515JA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1503, "ASUS G733PY/PZ/PZV/PYV", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
@@ -10586,7 +10902,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS),
SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY),
- SND_PCI_QUIRK(0x1043, 0x1eb3, "ROG Ally X RC72LA", ALC294_FIXUP_ASUS_ALLY_X),
SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
@@ -10600,6 +10915,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x1043, 0x1a63, "ASUS UX3405MA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1a8e, "ASUS G712LWS", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B),
SND_PCI_QUIRK(0x1043, 0x1b13, "ASUS U41SV/GA403U", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
@@ -10611,10 +10927,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1c63, "ASUS GU605M", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
+ SND_PCI_QUIRK(0x1043, 0x1c80, "ASUS VivoBook TP401", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS),
SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JU/JV/JI", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JY/JZ/JI/JG", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
- SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1ccf, "ASUS G814JU/JV/JI", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1cdf, "ASUS G814JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1cef, "ASUS G834JY/JZ/JI/JG", ALC285_FIXUP_ASUS_HEADSET_MIC),
@@ -10622,7 +10939,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606WA", ALC294_FIXUP_BASS_SPEAKER_15),
SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1e1f, "ASUS Vivobook 15 X1504VAP", ALC2XX_FIXUP_HEADSET_MIC),
@@ -10639,14 +10958,28 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1f1f, "ASUS H7604JI/JV/J3D", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x1f63, "ASUS P5405CSA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x1fb3, "ASUS ROG Flow Z13 GZ302EA", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x3011, "ASUS B5605CVA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
+ SND_PCI_QUIRK(0x1043, 0x3061, "ASUS B3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x3071, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30c1, "ASUS B3605CCA / P3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30d1, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x31d0, "ASUS Zen AIO 27 Z272SD_A272SD", ALC274_FIXUP_ASUS_ZEN_AIO_27),
+ SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+ SND_PCI_QUIRK(0x1043, 0x3d78, "ASUS GA603KH", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x3d88, "ASUS GA603KM", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x3e00, "ASUS G814FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x3e20, "ASUS G814PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x3e30, "ASUS TP3607SA", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x3ee0, "ASUS Strix G815_JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x3ef0, "ASUS Strix G635LR_LW_LX", ALC287_FIXUP_TAS2781_I2C),
@@ -10654,6 +10987,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x3f10, "ASUS Strix G835LR_LW_LX", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x3f30, "ASUS Strix G815LR_LW", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x3fd0, "ASUS B3605CVA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x3ff0, "ASUS B5405CVA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
@@ -10716,6 +11051,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x2624, "Clevo L240TU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x28c1, "Clevo V370VND", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1558, 0x35a1, "Clevo V3[56]0EN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x35b1, "Clevo V3[57]0WN[MNP]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -10743,6 +11080,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x51b1, "Clevo NS50AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x51b3, "Clevo NS70AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x5700, "Clevo X560WN[RST]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -10782,6 +11120,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0xa650, "Clevo NP[567]0SN[CD]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0xa671, "Clevo NP70SN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0xa741, "Clevo V54x_6x_TNE", ALC245_FIXUP_CLEVO_NOISY_MIC),
+ SND_PCI_QUIRK(0x1558, 0xa743, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC),
SND_PCI_QUIRK(0x1558, 0xa763, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC),
SND_PCI_QUIRK(0x1558, 0xb018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0xb019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -10852,6 +11191,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x17aa, 0x3384, "ThinkCentre M90a PRO", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
+ SND_PCI_QUIRK(0x17aa, 0x3386, "ThinkCentre M90a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
+ SND_PCI_QUIRK(0x17aa, 0x3387, "ThinkCentre M70a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C),
@@ -10923,6 +11265,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
+ SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC),
SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TAS2781_I2C),
@@ -10986,6 +11329,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13),
SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
@@ -11185,6 +11529,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"},
{.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"},
{.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"},
+ {.id = ALC285_FIXUP_HP_SPECTRE_X360_DF1, .name = "alc285-hp-spectre-x360-df1"},
{.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"},
{.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
{.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"},
@@ -11838,8 +12183,11 @@ static int patch_alc269(struct hda_codec *codec)
spec->codec_variant = ALC269_TYPE_ALC300;
spec->gen.mixer_nid = 0; /* no loopback on ALC300 */
break;
+ case 0x10ec0222:
case 0x10ec0623:
spec->codec_variant = ALC269_TYPE_ALC623;
+ spec->shutup = alc222_shutup;
+ spec->init_hook = alc222_init;
break;
case 0x10ec0700:
case 0x10ec0701:
diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig
index b75fbb3236a7..f5fa09d740b4 100644
--- a/sound/sh/Kconfig
+++ b/sound/sh/Kconfig
@@ -14,7 +14,7 @@ if SND_SUPERH
config SND_AICA
tristate "Dreamcast Yamaha AICA sound"
- depends on SH_DREAMCAST
+ depends on SH_DREAMCAST && SH_DMA_API
select SND_PCM
select G2_DMA
help
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index 92c5ff0deea2..607a3eaeb6da 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -101,7 +101,7 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
struct acp_stream *stream;
int slot_len, no_of_slots;
- chip = dev_get_platdata(dev);
+ chip = dev_get_drvdata(dev->parent);
switch (slot_width) {
case SLOT_WIDTH_8:
slot_len = 8;
diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c
index be01b178172e..e4af2640feeb 100644
--- a/sound/soc/amd/acp/acp-legacy-common.c
+++ b/sound/soc/amd/acp/acp-legacy-common.c
@@ -13,6 +13,7 @@
*/
#include "amd.h"
+#include <linux/acpi.h>
#include <linux/pci.h>
#include <linux/export.h>
@@ -445,7 +446,9 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
{
struct acpi_device *pdm_dev;
const union acpi_object *obj;
- u32 pdm_addr;
+ acpi_handle handle;
+ acpi_integer dmic_status;
+ u32 pdm_addr, ret;
switch (chip->acp_rev) {
case ACP3X_DEV:
@@ -477,6 +480,11 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
obj->integer.value == pdm_addr)
chip->is_pdm_dev = true;
}
+
+ handle = ACPI_HANDLE(&pci->dev);
+ ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
+ if (!ACPI_FAILURE(ret))
+ chip->is_pdm_dev = dmic_status;
}
}
EXPORT_SYMBOL_NS_GPL(check_acp_config, SND_SOC_ACP_COMMON);
diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c
index 3be401c72270..99a244f495bd 100644
--- a/sound/soc/amd/acp/acp-sdw-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c
@@ -267,7 +267,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card,
/* generate DAI links by each sdw link */
while (sof_dais->initialised) {
- int current_be_id;
+ int current_be_id = 0;
ret = create_sdw_dailink(card, sof_dais, dai_links,
&current_be_id, codec_conf);
diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h
index 39208305dd6c..f9759c9342cf 100644
--- a/sound/soc/amd/ps/acp63.h
+++ b/sound/soc/amd/ps/acp63.h
@@ -11,6 +11,7 @@
#define ACP_DEVICE_ID 0x15E2
#define ACP63_REG_START 0x1240000
#define ACP63_REG_END 0x125C000
+#define ACP63_PCI_REV 0x63
#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001
#define ACP_PGFSM_CNTL_POWER_ON_MASK 1
diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c
index 5c4a0be7a788..aec3150ecf58 100644
--- a/sound/soc/amd/ps/pci-ps.c
+++ b/sound/soc/amd/ps/pci-ps.c
@@ -559,7 +559,7 @@ static int snd_acp63_probe(struct pci_dev *pci,
/* Pink Sardine device check */
switch (pci->revision) {
- case 0x63:
+ case ACP63_PCI_REV:
break;
default:
dev_dbg(&pci->dev, "acp63 pci device not found\n");
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index b16587d8f97a..1689b6b22598 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -252,6 +252,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21M6"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21ME"),
}
},
@@ -308,6 +315,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83HN"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "83L3"),
}
},
@@ -335,6 +349,27 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "RB"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Nitro ANV15-41"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83J2"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83J3"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"),
}
@@ -346,7 +381,7 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "M5402RA"),
}
},
- {
+ {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -426,6 +461,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 17 D7VF"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
}
@@ -490,6 +532,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Victus by HP Gaming Laptop 15-fb2xxx"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_BOARD_NAME, "8A42"),
}
},
@@ -577,6 +626,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "pang13"),
}
},
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7UCX"),
+ }
+ },
{}
};
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index c9e7d40c47cc..4a4ec1c09e13 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -464,6 +464,28 @@ err:
return -EINVAL;
}
+static int mca_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ unsigned int mask, nchannels;
+
+ if (cl->tdm_slots) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mask = cl->tdm_tx_mask;
+ else
+ mask = cl->tdm_rx_mask;
+
+ nchannels = hweight32(mask);
+ } else {
+ nchannels = 2;
+ }
+
+ return snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 1, nchannels);
+}
+
static int mca_fe_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int slot_width)
{
@@ -680,6 +702,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops mca_fe_ops = {
+ .startup = mca_fe_startup,
.set_fmt = mca_fe_set_fmt,
.set_bclk_ratio = mca_set_bclk_ratio,
.set_tdm_slot = mca_fe_set_tdm_slot,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0d9d1d250f2b..6a72561c4189 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -746,10 +746,9 @@ config SND_SOC_CS_AMP_LIB
tristate
config SND_SOC_CS_AMP_LIB_TEST
- tristate "KUnit test for Cirrus Logic cs-amp-lib"
- depends on KUNIT
+ tristate "KUnit test for Cirrus Logic cs-amp-lib" if !KUNIT_ALL_TESTS
+ depends on SND_SOC_CS_AMP_LIB && KUNIT
default KUNIT_ALL_TESTS
- select SND_SOC_CS_AMP_LIB
help
This builds KUnit tests for the Cirrus Logic common
amplifier library.
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 402b9a2ff024..68cdb1027d0c 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -967,7 +967,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
priv->out_up_pending++;
- priv->out_up_delay += 17;
+ priv->out_up_delay += 17000;
break;
case ARIZONA_OUT4L_ENA_SHIFT:
case ARIZONA_OUT4R_ENA_SHIFT:
@@ -977,7 +977,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
case WM8997:
break;
default:
- priv->out_up_delay += 10;
+ priv->out_up_delay += 10000;
break;
}
break;
@@ -999,7 +999,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
if (!priv->out_up_pending && priv->out_up_delay) {
dev_dbg(component->dev, "Power up delay: %d\n",
priv->out_up_delay);
- msleep(priv->out_up_delay);
+ fsleep(priv->out_up_delay);
priv->out_up_delay = 0;
}
break;
@@ -1017,7 +1017,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
priv->out_down_pending++;
- priv->out_down_delay++;
+ priv->out_down_delay += 1000;
break;
case ARIZONA_OUT4L_ENA_SHIFT:
case ARIZONA_OUT4R_ENA_SHIFT:
@@ -1028,10 +1028,10 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
break;
case WM8998:
case WM1814:
- priv->out_down_delay += 5;
+ priv->out_down_delay += 5000;
break;
default:
- priv->out_down_delay++;
+ priv->out_down_delay += 1000;
break;
}
break;
@@ -1053,7 +1053,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
if (!priv->out_down_pending && priv->out_down_delay) {
dev_dbg(component->dev, "Power down delay: %d\n",
priv->out_down_delay);
- msleep(priv->out_down_delay);
+ fsleep(priv->out_down_delay);
priv->out_down_delay = 0;
}
break;
diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c
index a6db44520c06..f9b6bf7bea9c 100644
--- a/sound/soc/codecs/cs35l41-spi.c
+++ b/sound/soc/codecs/cs35l41-spi.c
@@ -32,13 +32,16 @@ static int cs35l41_spi_probe(struct spi_device *spi)
const struct regmap_config *regmap_config = &cs35l41_regmap_spi;
struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(&spi->dev);
struct cs35l41_private *cs35l41;
+ int ret;
cs35l41 = devm_kzalloc(&spi->dev, sizeof(struct cs35l41_private), GFP_KERNEL);
if (!cs35l41)
return -ENOMEM;
spi->max_speed_hz = CS35L41_SPI_MAX_FREQ;
- spi_setup(spi);
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return ret;
spi_set_drvdata(spi, cs35l41);
cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config);
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 195841a567c3..9007484b31c7 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -811,7 +811,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
break;
default:
dev_err(cs35l56_base->dev, "Unknown device %x\n", devid);
- return ret;
+ return -ENODEV;
}
cs35l56_base->type = devid & 0xFF;
diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
index d9ab003e166b..984a7f470a31 100644
--- a/sound/soc/codecs/cs42l43-jack.c
+++ b/sound/soc/codecs/cs42l43-jack.c
@@ -654,6 +654,10 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv)
reinit_completion(&priv->type_detect);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK);
+
cs42l43_start_hs_bias(priv, true);
regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT);
@@ -665,6 +669,9 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv)
CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT);
cs42l43_stop_hs_bias(priv);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, 0);
+
if (!time_left)
return -ETIMEDOUT;
@@ -702,6 +709,9 @@ static void cs42l43_clear_jack(struct cs42l43_codec *priv)
CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0);
regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL,
CS42L43_JACK_STEREO_CONFIG_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK);
regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
CS42L43_HSDET_MODE_MASK | CS42L43_HSDET_MANUAL_MODE_MASK,
0x2 << CS42L43_HSDET_MODE_SHIFT);
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index 8ec4083cd3b8..2c43e4a6751b 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -1146,7 +1146,7 @@ static const struct snd_kcontrol_new cs42l43_controls[] = {
SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2,
CS42L43_ADC_PGA_GAIN_SHIFT,
- 0xF, 5, cs42l43_adc_tlv),
+ 0xF, 4, cs42l43_adc_tlv),
SOC_DOUBLE("PDM1 Invert Switch", CS42L43_DMIC_PDM_CTRL,
CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0),
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index ddc00927313c..dc7794c9ac44 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -152,7 +152,7 @@ int hda_codec_probe_complete(struct hda_codec *codec)
ret = snd_hda_codec_build_controls(codec);
if (ret < 0) {
dev_err(&hdev->dev, "unable to create controls %d\n", ret);
- goto out;
+ return ret;
}
/* Bus suspended codecs as it does not manage their pm */
@@ -160,7 +160,7 @@ int hda_codec_probe_complete(struct hda_codec *codec)
/* rpm was forbidden in snd_hda_codec_device_new() */
snd_hda_codec_set_power_save(codec, 2000);
snd_hda_codec_register(codec);
-out:
+
/* Complement pm_runtime_get_sync(bus) in probe */
pm_runtime_mark_last_busy(bus->dev);
pm_runtime_put_autosuspend(bus->dev);
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index c989d82d1d3c..81bab8299eae 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -63,6 +63,10 @@
#define CDC_WSA_TX_SPKR_PROT_CLK_DISABLE 0
#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK GENMASK(3, 0)
#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K 0
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_16K 1
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_24K 2
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_32K 3
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_48K 4
#define CDC_WSA_TX0_SPKR_PROT_PATH_CFG0 (0x0248)
#define CDC_WSA_TX1_SPKR_PROT_PATH_CTL (0x0264)
#define CDC_WSA_TX1_SPKR_PROT_PATH_CFG0 (0x0268)
@@ -407,6 +411,7 @@ struct wsa_macro {
int ear_spkr_gain;
int spkr_gain_offset;
int spkr_mode;
+ u32 pcm_rate_vi;
int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX];
int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX];
struct regmap *regmap;
@@ -1280,6 +1285,7 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
+ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
int ret;
switch (substream->stream) {
@@ -1292,6 +1298,11 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
return ret;
}
break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+ if (dai->id == WSA_MACRO_AIF_VI)
+ wsa->pcm_rate_vi = params_rate(params);
+
+ break;
default:
break;
}
@@ -1448,35 +1459,11 @@ static void wsa_macro_mclk_enable(struct wsa_macro *wsa, bool mclk_enable)
}
}
-static int wsa_macro_mclk_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static void wsa_macro_enable_disable_vi_sense(struct snd_soc_component *component, bool enable,
+ u32 tx_reg0, u32 tx_reg1, u32 val)
{
- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
-
- wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU);
- return 0;
-}
-
-static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol,
- int event)
-{
- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
- u32 tx_reg0, tx_reg1;
-
- if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
- tx_reg0 = CDC_WSA_TX0_SPKR_PROT_PATH_CTL;
- tx_reg1 = CDC_WSA_TX1_SPKR_PROT_PATH_CTL;
- } else if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
- tx_reg0 = CDC_WSA_TX2_SPKR_PROT_PATH_CTL;
- tx_reg1 = CDC_WSA_TX3_SPKR_PROT_PATH_CTL;
- }
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- /* Enable V&I sensing */
+ if (enable) {
+ /* Enable V&I sensing */
snd_soc_component_update_bits(component, tx_reg0,
CDC_WSA_TX_SPKR_PROT_RESET_MASK,
CDC_WSA_TX_SPKR_PROT_RESET);
@@ -1485,10 +1472,10 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
CDC_WSA_TX_SPKR_PROT_RESET);
snd_soc_component_update_bits(component, tx_reg0,
CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK,
- CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K);
+ val);
snd_soc_component_update_bits(component, tx_reg1,
CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK,
- CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K);
+ val);
snd_soc_component_update_bits(component, tx_reg0,
CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
CDC_WSA_TX_SPKR_PROT_CLK_ENABLE);
@@ -1501,9 +1488,7 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component, tx_reg1,
CDC_WSA_TX_SPKR_PROT_RESET_MASK,
CDC_WSA_TX_SPKR_PROT_NO_RESET);
- break;
- case SND_SOC_DAPM_POST_PMD:
- /* Disable V&I sensing */
+ } else {
snd_soc_component_update_bits(component, tx_reg0,
CDC_WSA_TX_SPKR_PROT_RESET_MASK,
CDC_WSA_TX_SPKR_PROT_RESET);
@@ -1516,6 +1501,72 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component, tx_reg1,
CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
CDC_WSA_TX_SPKR_PROT_CLK_DISABLE);
+ }
+}
+
+static void wsa_macro_enable_disable_vi_feedback(struct snd_soc_component *component,
+ bool enable, u32 rate)
+{
+ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+ if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI]))
+ wsa_macro_enable_disable_vi_sense(component, enable,
+ CDC_WSA_TX0_SPKR_PROT_PATH_CTL,
+ CDC_WSA_TX1_SPKR_PROT_PATH_CTL, rate);
+
+ if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI]))
+ wsa_macro_enable_disable_vi_sense(component, enable,
+ CDC_WSA_TX2_SPKR_PROT_PATH_CTL,
+ CDC_WSA_TX3_SPKR_PROT_PATH_CTL, rate);
+}
+
+static int wsa_macro_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+ wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU);
+ return 0;
+}
+
+static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+ u32 rate_val;
+
+ switch (wsa->pcm_rate_vi) {
+ case 8000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K;
+ break;
+ case 16000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_16K;
+ break;
+ case 24000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_24K;
+ break;
+ case 32000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_32K;
+ break;
+ case 48000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_48K;
+ break;
+ default:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K;
+ break;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Enable V&I sensing */
+ wsa_macro_enable_disable_vi_feedback(component, true, rate_val);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* Disable V&I sensing */
+ wsa_macro_enable_disable_vi_feedback(component, false, rate_val);
break;
}
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c
index b24d6472ad5f..fbfd7fb7f168 100644
--- a/sound/soc/codecs/madera.c
+++ b/sound/soc/codecs/madera.c
@@ -2322,10 +2322,10 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
case CS42L92:
case CS47L92:
case CS47L93:
- out_up_delay = 6;
+ out_up_delay = 6000;
break;
default:
- out_up_delay = 17;
+ out_up_delay = 17000;
break;
}
@@ -2356,7 +2356,7 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
case MADERA_OUT3R_ENA_SHIFT:
priv->out_up_pending--;
if (!priv->out_up_pending) {
- msleep(priv->out_up_delay);
+ fsleep(priv->out_up_delay);
priv->out_up_delay = 0;
}
break;
@@ -2375,7 +2375,7 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
case MADERA_OUT3L_ENA_SHIFT:
case MADERA_OUT3R_ENA_SHIFT:
priv->out_down_pending++;
- priv->out_down_delay++;
+ priv->out_down_delay += 1000;
break;
default:
break;
@@ -2392,7 +2392,7 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
case MADERA_OUT3R_ENA_SHIFT:
priv->out_down_pending--;
if (!priv->out_down_pending) {
- msleep(priv->out_down_delay);
+ fsleep(priv->out_down_delay);
priv->out_down_delay = 0;
}
break;
diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h
index c234f2f4276a..78ada3a5bfae 100644
--- a/sound/soc/codecs/mt6359-accdet.h
+++ b/sound/soc/codecs/mt6359-accdet.h
@@ -123,6 +123,15 @@ struct mt6359_accdet {
struct workqueue_struct *jd_workqueue;
};
+#if IS_ENABLED(CONFIG_SND_SOC_MT6359_ACCDET)
int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack);
+#else
+static inline int
+mt6359_accdet_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack)
+{
+ return -EOPNOTSUPP;
+}
+#endif
#endif
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index fac0617ab95b..6cbb8d0535b0 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -493,9 +493,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
}
break;
case 24:
- if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) ||
- (format == SND_SOC_DAIFMT_DSP_B)) {
- dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n");
+ if (!provider_mode && ((format == SND_SOC_DAIFMT_DSP_A) ||
+ (format == SND_SOC_DAIFMT_DSP_B))) {
+ dev_err(component->dev, "24-bit slots not supported in consumer mode using DSP\n");
return -EINVAL;
}
break;
diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
index 5d99877f8839..e59bb77edf09 100644
--- a/sound/soc/codecs/pcm6240.c
+++ b/sound/soc/codecs/pcm6240.c
@@ -14,7 +14,7 @@
#include <linux/unaligned.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_irq.h>
@@ -2035,10 +2035,8 @@ static const struct regmap_config pcmdevice_i2c_regmap = {
static void pcmdevice_remove(struct pcmdevice_priv *pcm_dev)
{
- if (gpio_is_valid(pcm_dev->irq_info.gpio)) {
- gpio_free(pcm_dev->irq_info.gpio);
- free_irq(pcm_dev->irq_info.nmb, pcm_dev);
- }
+ if (pcm_dev->irq)
+ free_irq(pcm_dev->irq, pcm_dev);
mutex_destroy(&pcm_dev->codec_lock);
}
@@ -2110,7 +2108,7 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
ndev = 1;
dev_addrs[0] = i2c->addr;
}
- pcm_dev->irq_info.gpio = of_irq_get(np, 0);
+ pcm_dev->irq = of_irq_get(np, 0);
for (i = 0; i < ndev; i++)
pcm_dev->addr[i] = dev_addrs[i];
@@ -2133,22 +2131,10 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
if (pcm_dev->chip_id == PCM1690)
goto skip_interrupt;
- if (gpio_is_valid(pcm_dev->irq_info.gpio)) {
- dev_dbg(pcm_dev->dev, "irq-gpio = %d", pcm_dev->irq_info.gpio);
-
- ret = gpio_request(pcm_dev->irq_info.gpio, "PCMDEV-IRQ");
- if (!ret) {
- int gpio = pcm_dev->irq_info.gpio;
-
- gpio_direction_input(gpio);
- pcm_dev->irq_info.nmb = gpio_to_irq(gpio);
-
- } else
- dev_err(pcm_dev->dev, "%s: GPIO %d request error\n",
- __func__, pcm_dev->irq_info.gpio);
+ if (pcm_dev->irq) {
+ dev_dbg(pcm_dev->dev, "irq = %d", pcm_dev->irq);
} else
- dev_err(pcm_dev->dev, "Looking up irq-gpio failed %d\n",
- pcm_dev->irq_info.gpio);
+ dev_err(pcm_dev->dev, "No irq provided\n");
skip_interrupt:
ret = devm_snd_soc_register_component(&i2c->dev,
diff --git a/sound/soc/codecs/pcm6240.h b/sound/soc/codecs/pcm6240.h
index 1e125bb97286..2d8f9e798139 100644
--- a/sound/soc/codecs/pcm6240.h
+++ b/sound/soc/codecs/pcm6240.h
@@ -208,11 +208,6 @@ struct pcmdevice_regbin {
struct pcmdevice_config_info **cfg_info;
};
-struct pcmdevice_irqinfo {
- int gpio;
- int nmb;
-};
-
struct pcmdevice_priv {
struct snd_soc_component *component;
struct i2c_client *client;
@@ -221,7 +216,7 @@ struct pcmdevice_priv {
struct gpio_desc *hw_rst;
struct regmap *regmap;
struct pcmdevice_regbin regbin;
- struct pcmdevice_irqinfo irq_info;
+ int irq;
unsigned int addr[PCMDEVICE_MAX_I2C_DEVICES];
unsigned int chip_id;
int cur_conf;
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index f4e1ea29c265..8755a63478d7 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -2085,7 +2085,7 @@ static const struct reg_sequence rt1320_vc_patch_code_write[] = {
{ 0x3fc2bfc0, 0x03 },
{ 0x0000d486, 0x43 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 },
- { 0x1000db00, 0x04 },
+ { 0x1000db00, 0x07 },
{ 0x1000db01, 0x00 },
{ 0x1000db02, 0x11 },
{ 0x1000db03, 0x00 },
@@ -2106,6 +2106,21 @@ static const struct reg_sequence rt1320_vc_patch_code_write[] = {
{ 0x1000db12, 0x00 },
{ 0x1000db13, 0x00 },
{ 0x1000db14, 0x45 },
+ { 0x1000db15, 0x0d },
+ { 0x1000db16, 0x01 },
+ { 0x1000db17, 0x00 },
+ { 0x1000db18, 0x00 },
+ { 0x1000db19, 0xbf },
+ { 0x1000db1a, 0x13 },
+ { 0x1000db1b, 0x09 },
+ { 0x1000db1c, 0x00 },
+ { 0x1000db1d, 0x00 },
+ { 0x1000db1e, 0x00 },
+ { 0x1000db1f, 0x12 },
+ { 0x1000db20, 0x09 },
+ { 0x1000db21, 0x00 },
+ { 0x1000db22, 0x00 },
+ { 0x1000db23, 0x00 },
{ 0x0000d540, 0x01 },
{ 0x0000c081, 0xfc },
{ 0x0000f01e, 0x80 },
@@ -3705,6 +3720,9 @@ static int rt1320_read_prop(struct sdw_slave *slave)
/* set the timeout values */
prop->clk_stop_timeout = 64;
+ /* BIOS may set wake_capable. Make sure it is 0 as wake events are disabled. */
+ prop->wake_capable = 0;
+
return 0;
}
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 47df14ba5278..4f0236b34a2d 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -31,9 +31,7 @@
#include "rl6231.h"
#include "rt5665.h"
-#define RT5665_NUM_SUPPLIES 3
-
-static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = {
+static const char * const rt5665_supply_names[] = {
"AVDD",
"MICVDD",
"VBAT",
@@ -46,7 +44,6 @@ struct rt5665_priv {
struct gpio_desc *gpiod_ldo1_en;
struct gpio_desc *gpiod_reset;
struct snd_soc_jack *hs_jack;
- struct regulator_bulk_data supplies[RT5665_NUM_SUPPLIES];
struct delayed_work jack_detect_work;
struct delayed_work calibrate_work;
struct delayed_work jd_check_work;
@@ -4471,8 +4468,6 @@ static void rt5665_remove(struct snd_soc_component *component)
struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
regmap_write(rt5665->regmap, RT5665_RESET, 0);
-
- regulator_bulk_disable(ARRAY_SIZE(rt5665->supplies), rt5665->supplies);
}
#ifdef CONFIG_PM
@@ -4758,7 +4753,7 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)
{
struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5665_priv *rt5665;
- int i, ret;
+ int ret;
unsigned int val;
rt5665 = devm_kzalloc(&i2c->dev, sizeof(struct rt5665_priv),
@@ -4774,24 +4769,13 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)
else
rt5665_parse_dt(rt5665, &i2c->dev);
- for (i = 0; i < ARRAY_SIZE(rt5665->supplies); i++)
- rt5665->supplies[i].supply = rt5665_supply_names[i];
-
- ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5665->supplies),
- rt5665->supplies);
+ ret = devm_regulator_bulk_get_enable(&i2c->dev, ARRAY_SIZE(rt5665_supply_names),
+ rt5665_supply_names);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
- ret = regulator_bulk_enable(ARRAY_SIZE(rt5665->supplies),
- rt5665->supplies);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
- return ret;
- }
-
-
rt5665->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev,
"realtek,ldo1-en",
GPIOD_OUT_HIGH);
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index d5c985ff5ac5..bf83f4bc94fc 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -28,9 +28,50 @@ static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg)
0):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
0):
- case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
- 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
- RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03, RT722_SDCA_CTL_SELECTED_MODE,
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D,
+ RT722_SDCA_CTL_SELECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_MUTE, CH_01) ...
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_MUTE, CH_04):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26,
+ RT722_SDCA_CTL_VENDOR_DEF, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
+ RT722_SDCA_CTL_VENDOR_DEF, CH_08):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
return true;
default:
@@ -74,6 +115,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x5600000 ... 0x5600007:
case 0x5700000 ... 0x5700004:
case 0x5800000 ... 0x5800004:
+ case 0x5810000:
case 0x5b00003:
case 0x5c00011:
case 0x5d00006:
@@ -81,11 +123,16 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x5f00030:
case 0x6100000 ... 0x6100051:
case 0x6100055 ... 0x6100057:
+ case 0x6100060:
case 0x6100062:
case 0x6100064 ... 0x6100065:
case 0x6100067:
case 0x6100070 ... 0x610007c:
case 0x6100080:
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN,
+ CH_01) ...
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN,
+ CH_04):
case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
CH_01):
case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index d482cd194c08..e8fbe8a399f6 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -14,6 +14,7 @@
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
@@ -23,6 +24,11 @@
#include "tas2764.h"
+enum tas2764_devid {
+ DEVID_TAS2764 = 0,
+ DEVID_SN012776 = 1
+};
+
struct tas2764_priv {
struct snd_soc_component *component;
struct gpio_desc *reset_gpio;
@@ -30,7 +36,8 @@ struct tas2764_priv {
struct regmap *regmap;
struct device *dev;
int irq;
-
+ enum tas2764_devid devid;
+
int v_sense_slot;
int i_sense_slot;
@@ -180,33 +187,6 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new tas2764_asi1_mux =
SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
-static int tas2764_dac_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
- int ret;
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- tas2764->dac_powered = true;
- ret = tas2764_update_pwr_ctrl(tas2764);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- tas2764->dac_powered = false;
- ret = tas2764_update_pwr_ctrl(tas2764);
- break;
- default:
- dev_err(tas2764->dev, "Unsupported event\n");
- return -EINVAL;
- }
-
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
static const struct snd_kcontrol_new isense_switch =
SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1);
static const struct snd_kcontrol_new vsense_switch =
@@ -219,8 +199,7 @@ static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = {
1, &isense_switch),
SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN,
1, &vsense_switch),
- SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUTPUT("OUT"),
SND_SOC_DAPM_SIGGEN("VMON"),
SND_SOC_DAPM_SIGGEN("IMON")
@@ -241,9 +220,28 @@ static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction)
{
struct tas2764_priv *tas2764 =
snd_soc_component_get_drvdata(dai->component);
+ int ret;
+
+ if (!mute) {
+ tas2764->dac_powered = true;
+ ret = tas2764_update_pwr_ctrl(tas2764);
+ if (ret)
+ return ret;
+ }
tas2764->unmuted = !mute;
- return tas2764_update_pwr_ctrl(tas2764);
+ ret = tas2764_update_pwr_ctrl(tas2764);
+ if (ret)
+ return ret;
+
+ if (mute) {
+ tas2764->dac_powered = false;
+ ret = tas2764_update_pwr_ctrl(tas2764);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
@@ -365,7 +363,7 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
- u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0;
+ u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0, asi_cfg_4 = 0;
int ret;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -374,12 +372,14 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
fallthrough;
case SND_SOC_DAIFMT_NB_NF:
asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING;
+ asi_cfg_4 = TAS2764_TDM_CFG4_TX_FALLING;
break;
case SND_SOC_DAIFMT_IB_IF:
asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
fallthrough;
case SND_SOC_DAIFMT_IB_NF:
asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING;
+ asi_cfg_4 = TAS2764_TDM_CFG4_TX_RISING;
break;
}
@@ -389,6 +389,12 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
if (ret < 0)
return ret;
+ ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG4,
+ TAS2764_TDM_CFG4_TX_MASK,
+ asi_cfg_4);
+ if (ret < 0)
+ return ret;
+
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
@@ -526,10 +532,18 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = {
},
};
+static uint8_t sn012776_bop_presets[] = {
+ 0x01, 0x32, 0x02, 0x22, 0x83, 0x2d, 0x80, 0x02, 0x06,
+ 0x32, 0x46, 0x30, 0x02, 0x06, 0x38, 0x40, 0x30, 0x02,
+ 0x06, 0x3e, 0x37, 0x30, 0xff, 0xe6
+};
+
+static const struct regmap_config tas2764_i2c_regmap;
+
static int tas2764_codec_probe(struct snd_soc_component *component)
{
struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
- int ret;
+ int ret, i;
tas2764->component = component;
@@ -539,9 +553,10 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
}
tas2764_reset(tas2764);
+ regmap_reinit_cache(tas2764->regmap, &tas2764_i2c_regmap);
if (tas2764->irq) {
- ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff);
+ ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0x00);
if (ret < 0)
return ret;
@@ -578,6 +593,27 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
if (ret < 0)
return ret;
+ switch (tas2764->devid) {
+ case DEVID_SN012776:
+ ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
+ TAS2764_PWR_CTRL_BOP_SRC,
+ TAS2764_PWR_CTRL_BOP_SRC);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(sn012776_bop_presets); i++) {
+ ret = snd_soc_component_write(component,
+ TAS2764_BOP_CFG0 + i,
+ sn012776_bop_presets[i]);
+
+ if (ret < 0)
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
return 0;
}
@@ -626,6 +662,7 @@ static const struct reg_default tas2764_reg_defaults[] = {
{ TAS2764_TDM_CFG2, 0x0a },
{ TAS2764_TDM_CFG3, 0x10 },
{ TAS2764_TDM_CFG5, 0x42 },
+ { TAS2764_INT_CLK_CFG, 0x19 },
};
static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
@@ -643,6 +680,7 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
static bool tas2764_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case TAS2764_SW_RST:
case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:
case TAS2764_INT_CLK_CFG:
return true;
@@ -707,6 +745,8 @@ static int tas2764_i2c_probe(struct i2c_client *client)
if (!tas2764)
return -ENOMEM;
+ tas2764->devid = (enum tas2764_devid)of_device_get_match_data(&client->dev);
+
tas2764->dev = &client->dev;
tas2764->irq = client->irq;
i2c_set_clientdata(client, tas2764);
@@ -743,7 +783,8 @@ MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id tas2764_of_match[] = {
- { .compatible = "ti,tas2764" },
+ { .compatible = "ti,tas2764", .data = (void *)DEVID_TAS2764 },
+ { .compatible = "ti,sn012776", .data = (void *)DEVID_SN012776 },
{},
};
MODULE_DEVICE_TABLE(of, tas2764_of_match);
diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h
index 168af772a898..69c0f91cb423 100644
--- a/sound/soc/codecs/tas2764.h
+++ b/sound/soc/codecs/tas2764.h
@@ -25,10 +25,11 @@
/* Power Control */
#define TAS2764_PWR_CTRL TAS2764_REG(0X0, 0x02)
-#define TAS2764_PWR_CTRL_MASK GENMASK(1, 0)
+#define TAS2764_PWR_CTRL_MASK GENMASK(2, 0)
#define TAS2764_PWR_CTRL_ACTIVE 0x0
#define TAS2764_PWR_CTRL_MUTE BIT(0)
#define TAS2764_PWR_CTRL_SHUTDOWN BIT(1)
+#define TAS2764_PWR_CTRL_BOP_SRC BIT(7)
#define TAS2764_VSENSE_POWER_EN 3
#define TAS2764_ISENSE_POWER_EN 4
@@ -79,6 +80,12 @@
#define TAS2764_TDM_CFG3_RXS_SHIFT 0x4
#define TAS2764_TDM_CFG3_MASK GENMASK(3, 0)
+/* TDM Configuration Reg4 */
+#define TAS2764_TDM_CFG4 TAS2764_REG(0X0, 0x0d)
+#define TAS2764_TDM_CFG4_TX_MASK BIT(0)
+#define TAS2764_TDM_CFG4_TX_RISING 0x0
+#define TAS2764_TDM_CFG4_TX_FALLING BIT(0)
+
/* TDM Configuration Reg5 */
#define TAS2764_TDM_CFG5 TAS2764_REG(0X0, 0x0e)
#define TAS2764_TDM_CFG5_VSNS_MASK BIT(6)
@@ -110,4 +117,6 @@
#define TAS2764_INT_CLK_CFG TAS2764_REG(0x0, 0x5c)
#define TAS2764_INT_CLK_CFG_IRQZ_CLR BIT(2)
+#define TAS2764_BOP_CFG0 TAS2764_REG(0X0, 0x1d)
+
#endif /* __TAS2764__ */
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 9f93b230652a..0931b6109755 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -156,11 +156,37 @@ static const struct snd_kcontrol_new isense_switch =
static const struct snd_kcontrol_new vsense_switch =
SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1);
+static int sense_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);
+
+ /*
+ * Powering up ISENSE/VSENSE requires a trip through the shutdown state.
+ * Do that here to ensure that our changes are applied properly, otherwise
+ * we might end up with non-functional IVSENSE if playback started earlier,
+ * which would break software speaker protection.
+ */
+ switch (event) {
+ case SND_SOC_DAPM_PRE_REG:
+ return snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
+ TAS2770_PWR_CTRL_MASK,
+ TAS2770_PWR_CTRL_SHUTDOWN);
+ case SND_SOC_DAPM_POST_REG:
+ return tas2770_update_pwr_ctrl(tas2770);
+ default:
+ return 0;
+ }
+}
+
static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2770_asi1_mux),
- SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch),
- SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch),
+ SND_SOC_DAPM_SWITCH_E("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch,
+ sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_SWITCH_E("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch,
+ sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG),
SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_OUTPUT("OUT"),
@@ -506,7 +532,7 @@ static int tas2770_codec_probe(struct snd_soc_component *component)
}
static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
-static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -12750, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -10050, 50, 0);
static const struct snd_kcontrol_new tas2770_snd_controls[] = {
SOC_SINGLE_TLV("Speaker Playback Volume", TAS2770_PLAY_CFG_REG2,
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 373a31ddccb2..1375ac571fbf 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -17,7 +17,7 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <sound/tlv.h>
@@ -329,8 +329,7 @@ struct wcd9335_codec {
int comp_enabled[COMPANDER_MAX];
int intr1;
- int reset_gpio;
- struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
+ struct gpio_desc *reset_gpio;
unsigned int rx_port_value[WCD9335_RX_MAX];
unsigned int tx_port_value[WCD9335_TX_MAX];
@@ -353,6 +352,10 @@ struct wcd9335_irq {
char *name;
};
+static const char * const wcd9335_supplies[] = {
+ "vdd-buck", "vdd-buck-sido", "vdd-tx", "vdd-rx", "vdd-io",
+};
+
static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = {
WCD9335_SLIM_TX_CH(0),
WCD9335_SLIM_TX_CH(1),
@@ -4973,12 +4976,11 @@ static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = {
static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
{
struct device *dev = wcd->dev;
- struct device_node *np = dev->of_node;
int ret;
- wcd->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
- if (wcd->reset_gpio < 0)
- return dev_err_probe(dev, wcd->reset_gpio, "Reset GPIO missing from DT\n");
+ wcd->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd->reset_gpio), "Reset GPIO missing from DT\n");
wcd->mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(wcd->mclk))
@@ -4988,30 +4990,16 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
if (IS_ERR(wcd->native_clk))
return dev_err_probe(dev, PTR_ERR(wcd->native_clk), "slimbus clock not found\n");
- wcd->supplies[0].supply = "vdd-buck";
- wcd->supplies[1].supply = "vdd-buck-sido";
- wcd->supplies[2].supply = "vdd-tx";
- wcd->supplies[3].supply = "vdd-rx";
- wcd->supplies[4].supply = "vdd-io";
-
- ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd9335_supplies),
+ wcd9335_supplies);
if (ret)
- return dev_err_probe(dev, ret, "Failed to get supplies\n");
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
return 0;
}
static int wcd9335_power_on_reset(struct wcd9335_codec *wcd)
{
- struct device *dev = wcd->dev;
- int ret;
-
- ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, wcd->supplies);
- if (ret) {
- dev_err(dev, "Failed to get supplies: err = %d\n", ret);
- return ret;
- }
-
/*
* For WCD9335, it takes about 600us for the Vout_A and
* Vout_D to be ready after BUCK_SIDO is powered up.
@@ -5021,9 +5009,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd)
*/
usleep_range(600, 650);
- gpio_direction_output(wcd->reset_gpio, 0);
+ gpiod_set_value(wcd->reset_gpio, 1);
msleep(20);
- gpio_set_value(wcd->reset_gpio, 1);
+ gpiod_set_value(wcd->reset_gpio, 0);
msleep(20);
return 0;
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index 910852eb9698..c7f1b28f3b23 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -2273,7 +2273,7 @@ static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data)
{
struct wcd934x_codec *wcd = data;
unsigned long status = 0;
- int i, j, port_id;
+ unsigned int i, j, port_id;
unsigned int val, int_val = 0;
irqreturn_t ret = IRQ_NONE;
bool tx;
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index 08fb13a334a4..1df827a084ca 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -92,7 +92,6 @@ struct wcd937x_priv {
struct regmap_irq_chip *wcd_regmap_irq_chip;
struct regmap_irq_chip_data *irq_chip;
struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY];
- struct regulator *buck_supply;
struct snd_soc_jack *jack;
unsigned long status_mask;
s32 micb_ref[WCD937X_MAX_MICBIAS];
@@ -2564,6 +2563,7 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component)
ARRAY_SIZE(wcd9375_dapm_widgets));
if (ret < 0) {
dev_err(component->dev, "Failed to add snd_ctls\n");
+ wcd_clsh_ctrl_free(wcd937x->clsh_info);
return ret;
}
@@ -2571,6 +2571,7 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component)
ARRAY_SIZE(wcd9375_audio_map));
if (ret < 0) {
dev_err(component->dev, "Failed to add routes\n");
+ wcd_clsh_ctrl_free(wcd937x->clsh_info);
return ret;
}
}
@@ -2895,10 +2896,8 @@ static int wcd937x_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret, "Failed to get supplies\n");
ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
- if (ret) {
- regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
+ if (ret)
return dev_err_probe(dev, ret, "Failed to enable supplies\n");
- }
wcd937x_dt_parse_micbias_info(dev, wcd937x);
@@ -2934,7 +2933,6 @@ static int wcd937x_probe(struct platform_device *pdev)
err_disable_regulators:
regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
- regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
return ret;
}
@@ -2951,7 +2949,6 @@ static void wcd937x_remove(struct platform_device *pdev)
pm_runtime_dont_use_autosuspend(dev);
regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
- regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies);
}
#if defined(CONFIG_OF)
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index edd2cb185c42..9e67fbfc2cca 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -920,7 +920,7 @@ static int wm0010_spi_probe(struct spi_device *spi)
if (ret) {
dev_err(wm0010->dev, "Failed to set IRQ %d as wake source: %d\n",
irq, ret);
- return ret;
+ goto free_irq;
}
if (spi->max_speed_hz)
@@ -932,9 +932,18 @@ static int wm0010_spi_probe(struct spi_device *spi)
&soc_component_dev_wm0010, wm0010_dai,
ARRAY_SIZE(wm0010_dai));
if (ret < 0)
- return ret;
+ goto disable_irq_wake;
return 0;
+
+disable_irq_wake:
+ irq_set_irq_wake(wm0010->irq, 0);
+
+free_irq:
+ if (wm0010->irq)
+ free_irq(wm0010->irq, wm0010);
+
+ return ret;
}
static void wm0010_spi_remove(struct spi_device *spi)
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 502196253d42..64eee0d2347d 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -302,7 +302,7 @@ static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
} else {
wseq = wm5110_no_dre_left_enable;
nregs = ARRAY_SIZE(wm5110_no_dre_left_enable);
- priv->out_up_delay += 10;
+ priv->out_up_delay += 10000;
}
break;
case ARIZONA_OUT1R_ENA_SHIFT:
@@ -312,7 +312,7 @@ static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
} else {
wseq = wm5110_no_dre_right_enable;
nregs = ARRAY_SIZE(wm5110_no_dre_right_enable);
- priv->out_up_delay += 10;
+ priv->out_up_delay += 10000;
}
break;
default:
@@ -338,7 +338,7 @@ static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
snd_soc_component_update_bits(component,
ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG1, 0);
- priv->out_down_delay += 27;
+ priv->out_down_delay += 27000;
}
break;
case ARIZONA_OUT1R_ENA_SHIFT:
@@ -350,7 +350,7 @@ static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
snd_soc_component_update_bits(component,
ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG2, 0);
- priv->out_down_delay += 27;
+ priv->out_down_delay += 27000;
}
break;
default:
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index 47da5674d7c9..e31b7fb104e6 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -529,7 +529,7 @@ static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {
},
[WSA883X_PORT_VISENSE] = {
.num = WSA883X_PORT_VISENSE + 1,
- .ch_mask = 0x3,
+ .ch_mask = 0x1,
},
};
diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
index 86df5152c547..18b0ee8f15a5 100644
--- a/sound/soc/codecs/wsa884x.c
+++ b/sound/soc/codecs/wsa884x.c
@@ -891,7 +891,7 @@ static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = {
},
[WSA884X_PORT_VISENSE] = {
.num = WSA884X_PORT_VISENSE + 1,
- .ch_mask = 0x3,
+ .ch_mask = 0x1,
},
[WSA884X_PORT_CPS] = {
.num = WSA884X_PORT_CPS + 1,
@@ -1875,7 +1875,7 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp)
* Reading temperature is possible only when Power Amplifier is
* off. Report last cached data.
*/
- *temp = wsa884x->temperature;
+ *temp = wsa884x->temperature * 1000;
return 0;
}
@@ -1934,7 +1934,7 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp)
if ((val > WSA884X_LOW_TEMP_THRESHOLD) &&
(val < WSA884X_HIGH_TEMP_THRESHOLD)) {
wsa884x->temperature = val;
- *temp = val;
+ *temp = val * 1000;
ret = 0;
} else {
ret = -EAGAIN;
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 57b789d7fbed..5b4f20dbf7bb 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -199,12 +199,10 @@ static void i2s_start(struct dw_i2s_dev *dev,
else
i2s_write_reg(dev->i2s_base, IRER, 1);
- /* I2S needs to enable IRQ to make a handshake with DMAC on the JH7110 SoC */
- if (dev->use_pio || dev->is_jh7110)
- i2s_enable_irqs(dev, substream->stream, config->chan_nr);
- else
+ if (!(dev->use_pio || dev->is_jh7110))
i2s_enable_dma(dev, substream->stream);
+ i2s_enable_irqs(dev, substream->stream, config->chan_nr);
i2s_write_reg(dev->i2s_base, CER, 1);
}
@@ -218,11 +216,12 @@ static void i2s_stop(struct dw_i2s_dev *dev,
else
i2s_write_reg(dev->i2s_base, IRER, 0);
- if (dev->use_pio || dev->is_jh7110)
- i2s_disable_irqs(dev, substream->stream, 8);
- else
+ if (!(dev->use_pio || dev->is_jh7110))
i2s_disable_dma(dev, substream->stream);
+ i2s_disable_irqs(dev, substream->stream, 8);
+
+
if (!dev->active) {
i2s_write_reg(dev->i2s_base, CER, 0);
i2s_write_reg(dev->i2s_base, IER, 0);
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index bd5c46d763c0..ffd4a6ca5f3c 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -517,7 +517,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index));
regmap_update_bits(asrc->regmap, REG_ASRCTR,
- ASRCTR_USRi_MASK(index), 0);
+ ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index),
+ ASRCTR_USR(index));
/* Set the input and output clock sources */
regmap_update_bits(asrc->regmap, REG_ASRCSR,
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index f501f47242fb..1bba48318e2d 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -156,11 +156,24 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
for_each_dpcm_be(rtd, stream, dpcm) {
struct snd_soc_pcm_runtime *be = dpcm->be;
struct snd_pcm_substream *substream_be;
- struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(be, 0);
+ struct snd_soc_dai *dai_cpu = snd_soc_rtd_to_cpu(be, 0);
+ struct snd_soc_dai *dai_codec = snd_soc_rtd_to_codec(be, 0);
+ struct snd_soc_dai *dai;
if (dpcm->fe != rtd)
continue;
+ /*
+ * With audio graph card, original cpu dai is changed to codec
+ * device in backend, so if cpu dai is dummy device in backend,
+ * get the codec dai device, which is the real hardware device
+ * connected.
+ */
+ if (!snd_soc_dai_is_dummy(dai_cpu))
+ dai = dai_cpu;
+ else
+ dai = dai_codec;
+
substream_be = snd_soc_dpcm_get_substream(be, stream);
dma_params_be = snd_soc_dai_get_dma_data(dai, substream_be);
dev_be = dai->dev;
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index 3cd9a66b70a1..7981d598ba13 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -488,11 +488,17 @@ static int fsl_audmix_probe(struct platform_device *pdev)
goto err_disable_pm;
}
- priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0);
- if (IS_ERR(priv->pdev)) {
- ret = PTR_ERR(priv->pdev);
- dev_err(dev, "failed to register platform: %d\n", ret);
- goto err_disable_pm;
+ /*
+ * If dais property exist, then register the imx-audmix card driver.
+ * otherwise, it should be linked by audio graph card.
+ */
+ if (of_find_property(pdev->dev.of_node, "dais", NULL)) {
+ priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0);
+ if (IS_ERR(priv->pdev)) {
+ ret = PTR_ERR(priv->pdev);
+ dev_err(dev, "failed to register platform: %d\n", ret);
+ goto err_disable_pm;
+ }
}
return 0;
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index 8668abd35208..d41cb6f3efca 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -250,6 +250,9 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
bitmap_zero(prtd->chans_pending, 64);
+ prtd->buffer_ended = 0;
+ prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
for (i = 0; i < prtd->channels; i++)
prtd->qmc_dai->chans[i].prtd_tx = prtd;
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index c5efbceb06d1..25d4b27f5b76 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -771,13 +771,15 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
* anymore. Add software reset to fix this issue.
* This is a hardware bug, and will be fix in the
* next sai version.
+ *
+ * In consumer mode, this can happen even after a
+ * single open/close, especially if both tx and rx
+ * are running concurrently.
*/
- if (!sai->is_consumer_mode[tx]) {
- /* Software Reset */
- regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
- /* Clear SR bit to finish the reset */
- regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0);
- }
+ /* Software Reset */
+ regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
+ /* Clear SR bit to finish the reset */
+ regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0);
}
static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
index a7215bad6484..e5ae435171d6 100644
--- a/sound/soc/fsl/imx-card.c
+++ b/sound/soc/fsl/imx-card.c
@@ -516,7 +516,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
if (!card->dai_link)
return -ENOMEM;
- data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL);
+ data->link_data = devm_kcalloc(dev, num_links, sizeof(*link_data), GFP_KERNEL);
if (!data->link_data)
return -ENOMEM;
@@ -738,6 +738,8 @@ static int imx_card_probe(struct platform_device *pdev)
data->dapm_routes[i].sink =
devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s",
i + 1, "Playback");
+ if (!data->dapm_routes[i].sink)
+ return -ENOMEM;
data->dapm_routes[i].source = "CPU-Playback";
}
}
@@ -755,6 +757,8 @@ static int imx_card_probe(struct platform_device *pdev)
data->dapm_routes[i].source =
devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s",
i + 1, "Capture");
+ if (!data->dapm_routes[i].source)
+ return -ENOMEM;
data->dapm_routes[i].sink = "CPU-Capture";
}
}
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index fedae7f6f70c..809dbb9ded36 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -1097,6 +1097,7 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep,
args.np = ep;
dai = snd_soc_get_dai_via_args(&args);
if (dai) {
+ dlc->of_node = node;
dlc->dai_name = snd_soc_dai_name_get(dai);
dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
if (!dlc->dai_args)
@@ -1149,9 +1150,9 @@ void graph_util_parse_link_direction(struct device_node *np,
bool is_playback_only = of_property_read_bool(np, "playback-only");
bool is_capture_only = of_property_read_bool(np, "capture-only");
- if (is_playback_only)
+ if (playback_only)
*playback_only = is_playback_only;
- if (is_capture_only)
+ if (capture_only)
*capture_only = is_capture_only;
}
EXPORT_SYMBOL_GPL(graph_util_parse_link_direction);
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
index 1767ded4d983..c9978fb9c74e 100644
--- a/sound/soc/intel/avs/debugfs.c
+++ b/sound/soc/intel/avs/debugfs.c
@@ -372,7 +372,10 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s
return ret;
num_elems = *array;
- resource_mask = array[1];
+ if (!num_elems) {
+ ret = -EINVAL;
+ goto free_array;
+ }
/*
* Disable if just resource mask is provided - no log priority flags.
@@ -380,6 +383,7 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s
* Enable input format: mask, prio1, .., prioN
* Where 'N' equals number of bits set in the 'mask'.
*/
+ resource_mask = array[1];
if (num_elems == 1) {
ret = disable_logs(adev, resource_mask);
} else {
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 4fba46e77c47..eff1d46040da 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -169,7 +169,9 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg
dev_crit(adev->dev, "communication severed, rebooting dsp..\n");
- cancel_delayed_work_sync(&ipc->d0ix_work);
+ /* Avoid deadlock as the exception may be the response to SET_D0IX. */
+ if (current_work() != &ipc->d0ix_work.work)
+ cancel_delayed_work_sync(&ipc->d0ix_work);
ipc->in_d0ix = false;
/* Re-enabled on recovery completion. */
pm_runtime_disable(adev->dev);
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 945f9c0a6a54..15defce0f3eb 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -925,7 +925,8 @@ static int avs_component_probe(struct snd_soc_component *component)
else
mach->tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,
"hda-generic-tplg.bin");
-
+ if (!mach->tplg_filename)
+ return -ENOMEM;
filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
mach->tplg_filename);
if (!filename)
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index cc10ae58b0c7..8dee46abf346 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -42,6 +42,7 @@ config SND_SOC_INTEL_SOF_NUVOTON_COMMON
tristate
config SND_SOC_INTEL_SOF_BOARD_HELPERS
+ select SND_SOC_ACPI_INTEL_MATCH
tristate
if SND_SOC_INTEL_CATPT
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 1148e9498d8e..b6434b473126 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -576,6 +576,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
+ { /* Acer Aspire SW3-013 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-013"),
+ },
+ .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+ BYT_RT5640_JD_SRC_JD2_IN4N |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_0P75 |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index 84fc35d88b92..5911a0558651 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -13,6 +13,7 @@
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <linux/soundwire/sdw_intel.h>
+#include <sound/core.h>
#include <sound/soc-acpi.h>
#include "sof_sdw_common.h"
#include "../../codecs/rt711.h"
@@ -685,6 +686,24 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
{}
};
+static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = {
+ SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC),
+ {}
+};
+
+static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach)
+{
+ const struct snd_pci_quirk *quirk_entry;
+
+ quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor,
+ mach->mach_params.subsystem_device,
+ sof_sdw_ssid_quirk_table);
+
+ if (quirk_entry)
+ sof_sdw_quirk = quirk_entry->value;
+}
+
static struct snd_soc_dai_link_component platform_component[] = {
{
/* name might be overridden during probe */
@@ -853,7 +872,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card,
/* generate DAI links by each sdw link */
while (sof_dais->initialised) {
- int current_be_id;
+ int current_be_id = 0;
ret = create_sdw_dailink(card, sof_dais, dai_links,
&current_be_id, codec_conf);
@@ -1212,6 +1231,13 @@ static int mc_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(card, ctx);
+ if (mach->mach_params.subsystem_id_set) {
+ snd_soc_card_set_pci_ssid(card,
+ mach->mach_params.subsystem_vendor,
+ mach->mach_params.subsystem_device);
+ sof_sdw_check_ssid_quirk(mach);
+ }
+
dmi_check_system(sof_sdw_quirk_table);
if (quirk_override != -1) {
@@ -1227,12 +1253,6 @@ static int mc_probe(struct platform_device *pdev)
for (i = 0; i < ctx->codec_info_list_count; i++)
codec_info_list[i].amp_num = 0;
- if (mach->mach_params.subsystem_id_set) {
- snd_soc_card_set_pci_ssid(card,
- mach->mach_params.subsystem_vendor,
- mach->mach_params.subsystem_device);
- }
-
ret = sof_card_dai_links_create(card);
if (ret < 0)
return ret;
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index 91e146e2487d..a9a740e24969 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -14,7 +14,7 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc
soc-acpi-intel-lnl-match.o \
soc-acpi-intel-ptl-match.o \
soc-acpi-intel-hda-match.o \
- soc-acpi-intel-sdw-mockup-match.o
+ soc-acpi-intel-sdw-mockup-match.o sof-function-topology-lib.o
snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
index bb1324fb588e..a68efbe98948 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -214,6 +214,15 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_2_group2_adr[] = {
+ {
+ .adr = 0x000232025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1316_1_single_adr[] = {
{
.adr = 0x000130025D131601ull,
@@ -547,6 +556,20 @@ static const struct snd_soc_acpi_link_adr adl_chromebook_base[] = {
{}
};
+static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link02[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
+ .adr_d = rt1316_0_group2_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1316_2_group2_adr),
+ .adr_d = rt1316_2_group2_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_codecs adl_max98357a_amp = {
.num_codecs = 1,
.codecs = {"MX98357A"}
@@ -749,6 +772,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-adl-sdw-max98373-rt5682.tplg",
},
+ {
+ .link_mask = BIT(0) | BIT(2),
+ .links = adl_sdw_rt1316_link02,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-adl-rt1316-l02.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
index 24d850df77ca..1ad704ca2c5f 100644
--- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
@@ -8,6 +8,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
#include <sound/soc-acpi-intel-ssp-common.h>
+#include "sof-function-topology-lib.h"
static const struct snd_soc_acpi_endpoint single_endpoint = {
.num = 0,
@@ -138,7 +139,7 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_r1_adr[] = {
},
};
-static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = {
+static const struct snd_soc_acpi_adr_device cs35l56_3_l3_adr[] = {
{
.adr = 0x00033301fa355601ull,
.num_endpoints = 1,
@@ -147,6 +148,24 @@ static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = {
},
};
+static const struct snd_soc_acpi_adr_device cs35l56_2_r3_adr[] = {
+ {
+ .adr = 0x00023301fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = {
+ {
+ .adr = 0x00033101fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+};
+
static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
{ /* Jack Playback Endpoint */
.num = 0,
@@ -306,6 +325,25 @@ static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_2_l23[] = {
},
{
.mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_l3_adr),
+ .adr_d = cs35l56_3_l3_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_3_l23[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs35l56_2_r3_adr),
+ .adr_d = cs35l56_2_r3_adr,
+ },
+ {
+ .mask = BIT(3),
.num_adr = ARRAY_SIZE(cs35l56_3_l1_adr),
.adr_d = cs35l56_3_l1_adr,
},
@@ -399,36 +437,49 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.links = arl_cs42l43_l0_cs35l56_l23,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2) | BIT(3),
.links = arl_cs42l43_l0_cs35l56_2_l23,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0) | BIT(2) | BIT(3),
+ .links = arl_cs42l43_l0_cs35l56_3_l23,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2),
.links = arl_cs42l43_l0_cs35l56_l2,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = arl_cs42l43_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-cs42l43-l0.tplg",
- },
- {
- .link_mask = BIT(2),
- .links = arl_cs42l43_l2,
- .drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(2) | BIT(3),
.links = arl_cs42l43_l2_cs35l56_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(2),
+ .links = arl_cs42l43_l2,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = 0x1, /* link0 required */
@@ -447,6 +498,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.links = arl_rt722_l0_rt1320_l2,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index fd02c864e25e..a3f791765637 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -297,7 +297,7 @@ static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = {
static const struct snd_soc_acpi_adr_device rt1318_1_single_adr[] = {
{
- .adr = 0x000130025D131801,
+ .adr = 0x000130025D131801ull,
.num_endpoints = 1,
.endpoints = &single_endpoint,
.name_prefix = "rt1318-1"
diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c
new file mode 100644
index 000000000000..3cc81dcf047e
--- /dev/null
+++ b/sound/soc/intel/common/sof-function-topology-lib.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2025 Intel Corporation.
+//
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "sof-function-topology-lib.h"
+
+enum tplg_device_id {
+ TPLG_DEVICE_SDCA_JACK,
+ TPLG_DEVICE_SDCA_AMP,
+ TPLG_DEVICE_SDCA_MIC,
+ TPLG_DEVICE_INTEL_PCH_DMIC,
+ TPLG_DEVICE_HDMI,
+ TPLG_DEVICE_MAX
+};
+
+#define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \
+ BIT(TPLG_DEVICE_SDCA_MIC))
+
+#define SOF_INTEL_PLATFORM_NAME_MAX 4
+
+int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
+ const char *prefix, const char ***tplg_files)
+{
+ struct snd_soc_acpi_mach_params mach_params = mach->mach_params;
+ struct snd_soc_dai_link *dai_link;
+ const struct firmware *fw;
+ char platform[SOF_INTEL_PLATFORM_NAME_MAX];
+ unsigned long tplg_mask = 0;
+ int tplg_num = 0;
+ int tplg_dev;
+ int ret;
+ int i;
+
+ ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform);
+ if (ret != 1) {
+ dev_err(card->dev, "Invalid platform name %s of tplg %s\n",
+ platform, mach->sof_tplg_filename);
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ char *tplg_dev_name;
+
+ dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id);
+ if (strstr(dai_link->name, "SimpleJack")) {
+ tplg_dev = TPLG_DEVICE_SDCA_JACK;
+ tplg_dev_name = "sdca-jack";
+ } else if (strstr(dai_link->name, "SmartAmp")) {
+ tplg_dev = TPLG_DEVICE_SDCA_AMP;
+ tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL,
+ "sdca-%damp", dai_link->num_cpus);
+ if (!tplg_dev_name)
+ return -ENOMEM;
+ } else if (strstr(dai_link->name, "SmartMic")) {
+ tplg_dev = TPLG_DEVICE_SDCA_MIC;
+ tplg_dev_name = "sdca-mic";
+ } else if (strstr(dai_link->name, "dmic")) {
+ switch (mach_params.dmic_num) {
+ case 2:
+ tplg_dev_name = "dmic-2ch";
+ break;
+ case 4:
+ tplg_dev_name = "dmic-4ch";
+ break;
+ default:
+ dev_warn(card->dev,
+ "unsupported number of dmics: %d\n",
+ mach_params.dmic_num);
+ continue;
+ }
+ tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC;
+ } else if (strstr(dai_link->name, "iDisp")) {
+ tplg_dev = TPLG_DEVICE_HDMI;
+ tplg_dev_name = "hdmi-pcm5";
+
+ } else {
+ /* The dai link is not supported by separated tplg yet */
+ dev_dbg(card->dev,
+ "dai_link %s is not supported by separated tplg yet\n",
+ dai_link->name);
+ return 0;
+ }
+ if (tplg_mask & BIT(tplg_dev))
+ continue;
+
+ tplg_mask |= BIT(tplg_dev);
+
+ /*
+ * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg
+ * where <platform> is only required for the DMIC function as the nhlt blob
+ * is platform dependent.
+ */
+ switch (tplg_dev) {
+ case TPLG_DEVICE_INTEL_PCH_DMIC:
+ (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s/sof-%s-%s-id%d.tplg",
+ prefix, platform,
+ tplg_dev_name, dai_link->id);
+ break;
+ default:
+ (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s/sof-%s-id%d.tplg",
+ prefix, tplg_dev_name,
+ dai_link->id);
+ break;
+ }
+ if (!(*tplg_files)[tplg_num])
+ return -ENOMEM;
+ tplg_num++;
+ }
+
+ dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);
+
+ /* Check presence of sub-topologies */
+ for (i = 0; i < tplg_num; i++) {
+ ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev);
+ if (!ret) {
+ release_firmware(fw);
+ } else {
+ dev_dbg(card->dev, "Failed to open topology file: %s\n", (*tplg_files)[i]);
+ return 0;
+ }
+ }
+
+ return tplg_num;
+}
+
diff --git a/sound/soc/intel/common/sof-function-topology-lib.h b/sound/soc/intel/common/sof-function-topology-lib.h
new file mode 100644
index 000000000000..e7d0c39d0788
--- /dev/null
+++ b/sound/soc/intel/common/sof-function-topology-lib.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * soc-acpi-intel-get-tplg.h - get-tplg-files ops
+ *
+ * Copyright (c) 2025, Intel Corporation.
+ *
+ */
+
+#ifndef _SND_SOC_ACPI_INTEL_GET_TPLG_H
+#define _SND_SOC_ACPI_INTEL_GET_TPLG_H
+
+int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
+ const char *prefix, const char ***tplg_files);
+
+#endif
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
index e69c1bb2cb23..7f411b857782 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
@@ -58,7 +58,15 @@ static const char *aud_clks[MT8188_CLK_NUM] = {
[MT8188_CLK_AUD_ADC] = "aud_adc",
[MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires",
[MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp",
+ [MT8188_CLK_AUD_AFE_DMIC1] = "aud_afe_dmic1",
+ [MT8188_CLK_AUD_AFE_DMIC2] = "aud_afe_dmic2",
+ [MT8188_CLK_AUD_AFE_DMIC3] = "aud_afe_dmic3",
+ [MT8188_CLK_AUD_AFE_DMIC4] = "aud_afe_dmic4",
[MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires",
+ [MT8188_CLK_AUD_DMIC_HIRES1] = "aud_dmic_hires1",
+ [MT8188_CLK_AUD_DMIC_HIRES2] = "aud_dmic_hires2",
+ [MT8188_CLK_AUD_DMIC_HIRES3] = "aud_dmic_hires3",
+ [MT8188_CLK_AUD_DMIC_HIRES4] = "aud_dmic_hires4",
[MT8188_CLK_AUD_I2SIN] = "aud_i2sin",
[MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in",
[MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out",
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
index ec53c171c170..c6c78d684f3e 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
@@ -54,7 +54,15 @@ enum {
MT8188_CLK_AUD_ADC,
MT8188_CLK_AUD_DAC_HIRES,
MT8188_CLK_AUD_A1SYS_HP,
+ MT8188_CLK_AUD_AFE_DMIC1,
+ MT8188_CLK_AUD_AFE_DMIC2,
+ MT8188_CLK_AUD_AFE_DMIC3,
+ MT8188_CLK_AUD_AFE_DMIC4,
MT8188_CLK_AUD_ADC_HIRES,
+ MT8188_CLK_AUD_DMIC_HIRES1,
+ MT8188_CLK_AUD_DMIC_HIRES2,
+ MT8188_CLK_AUD_DMIC_HIRES3,
+ MT8188_CLK_AUD_DMIC_HIRES4,
MT8188_CLK_AUD_I2SIN,
MT8188_CLK_AUD_TDM_IN,
MT8188_CLK_AUD_I2S_OUT,
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
index 73e5c63aeec8..d36520c6272d 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -2855,10 +2855,6 @@ static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg)
case AFE_DMIC3_SRC_DEBUG_MON0:
case AFE_DMIC3_UL_SRC_MON0:
case AFE_DMIC3_UL_SRC_MON1:
- case DMIC_GAIN1_CUR:
- case DMIC_GAIN2_CUR:
- case DMIC_GAIN3_CUR:
- case DMIC_GAIN4_CUR:
case ETDM_IN1_MONITOR:
case ETDM_IN2_MONITOR:
case ETDM_OUT1_MONITOR:
diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
index 8ebf6c7502aa..400cec09c3a3 100644
--- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c
+++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
@@ -822,12 +822,12 @@ SND_SOC_DAILINK_DEFS(ETDM1_IN_BE,
SND_SOC_DAILINK_DEFS(ETDM2_IN_BE,
DAILINK_COMP_ARRAY(COMP_CPU("ETDM2_IN")),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(ETDM1_OUT_BE,
DAILINK_COMP_ARRAY(COMP_CPU("ETDM1_OUT")),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(ETDM2_OUT_BE,
diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
index 11b9a5bc7163..89575bb8afed 100644
--- a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
@@ -812,11 +812,10 @@ static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
static int mt8365_dai_i2s_set_priv(struct mtk_base_afe *afe)
{
int i, ret;
- struct mt8365_afe_private *afe_priv = afe->platform_priv;
for (i = 0; i < DAI_I2S_NUM; i++) {
ret = mt8365_dai_set_priv(afe, mt8365_i2s_priv[i].id,
- sizeof(*afe_priv),
+ sizeof(mt8365_i2s_priv[i]),
&mt8365_i2s_priv[i]);
if (ret)
return ret;
diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c
index 1a4ef124e4e2..ad38c74166a4 100644
--- a/sound/soc/meson/meson-card-utils.c
+++ b/sound/soc/meson/meson-card-utils.c
@@ -231,7 +231,7 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card,
const char *p))
{
/* If property is not provided, don't fail ... */
- if (!of_property_read_bool(card->dev->of_node, propname))
+ if (!of_property_present(card->dev->of_node, propname))
return 0;
/* ... but do fail if it is provided and the parsing fails */
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 27a2bf9a6613..de3ec6f594c1 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -13,10 +13,11 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <dt-bindings/sound/qcom,lpass.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
#include "lpass-hdmi.h"
#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
-#define LPASS_MAX_PORTS (LPASS_CDC_DMA_VA_TX8 + 1)
+#define LPASS_MAX_PORTS (DISPLAY_PORT_RX_7 + 1)
#define LPASS_MAX_MI2S_PORTS (8)
#define LPASS_MAX_DMA_CHANNELS (8)
#define LPASS_MAX_HDMI_DMA_CHANNELS (4)
diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c
index c9404b5934c7..2cd522108221 100644
--- a/sound/soc/qcom/qdsp6/q6apm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6apm-dai.c
@@ -24,8 +24,8 @@
#define PLAYBACK_MIN_PERIOD_SIZE 128
#define CAPTURE_MIN_NUM_PERIODS 2
#define CAPTURE_MAX_NUM_PERIODS 8
-#define CAPTURE_MAX_PERIOD_SIZE 4096
-#define CAPTURE_MIN_PERIOD_SIZE 320
+#define CAPTURE_MAX_PERIOD_SIZE 65536
+#define CAPTURE_MIN_PERIOD_SIZE 6144
#define BUFFER_BYTES_MAX (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE)
#define BUFFER_BYTES_MIN (PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE)
#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
@@ -64,12 +64,12 @@ struct q6apm_dai_rtd {
phys_addr_t phys;
unsigned int pcm_size;
unsigned int pcm_count;
- unsigned int pos; /* Buffer position */
unsigned int periods;
unsigned int bytes_sent;
unsigned int bytes_received;
unsigned int copied_total;
uint16_t bits_per_sample;
+ snd_pcm_uframes_t queue_ptr;
bool next_track;
enum stream_state state;
struct q6apm_graph *graph;
@@ -123,25 +123,16 @@ static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *
{
struct q6apm_dai_rtd *prtd = priv;
struct snd_pcm_substream *substream = prtd->substream;
- unsigned long flags;
switch (opcode) {
case APM_CLIENT_EVENT_CMD_EOS_DONE:
prtd->state = Q6APM_STREAM_STOPPED;
break;
case APM_CLIENT_EVENT_DATA_WRITE_DONE:
- spin_lock_irqsave(&prtd->lock, flags);
- prtd->pos += prtd->pcm_count;
- spin_unlock_irqrestore(&prtd->lock, flags);
snd_pcm_period_elapsed(substream);
- if (prtd->state == Q6APM_STREAM_RUNNING)
- q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0);
break;
case APM_CLIENT_EVENT_DATA_READ_DONE:
- spin_lock_irqsave(&prtd->lock, flags);
- prtd->pos += prtd->pcm_count;
- spin_unlock_irqrestore(&prtd->lock, flags);
snd_pcm_period_elapsed(substream);
if (prtd->state == Q6APM_STREAM_RUNNING)
q6apm_read(prtd->graph);
@@ -248,7 +239,6 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
}
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
- prtd->pos = 0;
/* rate and channels are sent to audio driver */
ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);
if (ret < 0) {
@@ -294,6 +284,27 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
return 0;
}
+static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+ int i, ret = 0, avail_periods;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size;
+ for (i = 0; i < avail_periods; i++) {
+ ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ if (ret < 0) {
+ dev_err(component->dev, "Error queuing playback buffer %d\n", ret);
+ return ret;
+ }
+ prtd->queue_ptr += runtime->period_size;
+ }
+ }
+
+ return ret;
+}
+
static int q6apm_dai_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
@@ -305,9 +316,6 @@ static int q6apm_dai_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- /* start writing buffers for playback only as we already queued capture buffers */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0);
break;
case SNDRV_PCM_TRIGGER_STOP:
/* TODO support be handled via SoftPause Module */
@@ -377,13 +385,14 @@ static int q6apm_dai_open(struct snd_soc_component *component,
}
}
- ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+ /* setup 10ms latency to accommodate DSP restrictions */
+ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480);
if (ret < 0) {
dev_err(dev, "constraint for period bytes step ret = %d\n", ret);
goto err;
}
- ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480);
if (ret < 0) {
dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret);
goto err;
@@ -428,16 +437,12 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
struct q6apm_dai_rtd *prtd = runtime->private_data;
snd_pcm_uframes_t ptr;
- unsigned long flags;
- spin_lock_irqsave(&prtd->lock, flags);
- if (prtd->pos == prtd->pcm_size)
- prtd->pos = 0;
-
- ptr = bytes_to_frames(runtime, prtd->pos);
- spin_unlock_irqrestore(&prtd->lock, flags);
+ ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size;
+ if (ptr)
+ return ptr - 1;
- return ptr;
+ return 0;
}
static int q6apm_dai_hw_params(struct snd_soc_component *component,
@@ -652,8 +657,6 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component,
prtd->pcm_size = runtime->fragments * runtime->fragment_size;
prtd->bits_per_sample = 16;
- prtd->pos = 0;
-
if (prtd->next_track != true) {
memcpy(&prtd->codec, codec, sizeof(*codec));
@@ -836,6 +839,7 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = {
.hw_params = q6apm_dai_hw_params,
.pointer = q6apm_dai_pointer,
.trigger = q6apm_dai_trigger,
+ .ack = q6apm_dai_ack,
.compress_ops = &q6apm_dai_compress_ops,
.use_dai_pcm_id = true,
};
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 2a2a5bd98110..ca57413cb784 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -494,6 +494,19 @@ int q6apm_read(struct q6apm_graph *graph)
}
EXPORT_SYMBOL_GPL(q6apm_read);
+int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir)
+{
+ struct audioreach_graph_data *data;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ data = &graph->rx_data;
+ else
+ data = &graph->tx_data;
+
+ return (int)atomic_read(&data->hw_ptr);
+}
+EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer);
+
static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
{
struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done;
@@ -520,7 +533,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
done = data->payload;
phys = graph->rx_data.buf[token].phys;
mutex_unlock(&graph->lock);
-
+ /* token numbering starts at 0 */
+ atomic_set(&graph->rx_data.hw_ptr, token + 1);
if (lower_32_bits(phys) == done->buf_addr_lsw &&
upper_32_bits(phys) == done->buf_addr_msw) {
graph->result.opcode = hdr->opcode;
@@ -553,6 +567,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
rd_done = data->payload;
phys = graph->tx_data.buf[hdr->token].phys;
mutex_unlock(&graph->lock);
+ /* token numbering starts at 0 */
+ atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
lower_32_bits(phys) == rd_done->buf_addr_lsw) {
diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h
index c248c8d2b1ab..7ce08b401e31 100644
--- a/sound/soc/qcom/qdsp6/q6apm.h
+++ b/sound/soc/qcom/qdsp6/q6apm.h
@@ -2,6 +2,7 @@
#ifndef __Q6APM_H__
#define __Q6APM_H__
#include <linux/types.h>
+#include <linux/atomic.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/kernel.h>
@@ -77,6 +78,7 @@ struct audioreach_graph_data {
uint32_t num_periods;
uint32_t dsp_buf;
uint32_t mem_map_handle;
+ atomic_t hw_ptr;
};
struct audioreach_graph {
@@ -150,4 +152,5 @@ int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph,
int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);
int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);
int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph, uint32_t codec_id);
+int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir);
#endif /* __APM_GRAPH_ */
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 045100c94352..a400c9a31fea 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -892,9 +892,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
if (ret < 0) {
dev_err(dev, "q6asm_open_write failed\n");
- q6asm_audio_client_free(prtd->audio_client);
- prtd->audio_client = NULL;
- return ret;
+ goto open_err;
}
}
@@ -903,7 +901,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
prtd->session_id, dir);
if (ret) {
dev_err(dev, "Stream reg failed ret:%d\n", ret);
- return ret;
+ goto q6_err;
}
ret = __q6asm_dai_compr_set_codec_params(component, stream,
@@ -911,7 +909,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
prtd->stream_id);
if (ret) {
dev_err(dev, "codec param setup failed ret:%d\n", ret);
- return ret;
+ goto q6_err;
}
ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
@@ -920,12 +918,21 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
if (ret < 0) {
dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto q6_err;
}
prtd->state = Q6ASM_STREAM_RUNNING;
return 0;
+
+q6_err:
+ q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
+
+open_err:
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return ret;
}
static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index a479d7e5b7fb..314ff68506d9 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -91,6 +91,10 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
else
ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt,
tx_ch, 0, NULL);
+ if (ret != 0 && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "failed to set cpu chan map, err:%d\n", ret);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
index 19adadedc88a..1001fd321380 100644
--- a/sound/soc/qcom/sm8250.c
+++ b/sound/soc/qcom/sm8250.c
@@ -7,6 +7,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <linux/soundwire/sdw.h>
#include <sound/jack.h>
#include <linux/input-event-codes.h>
@@ -39,9 +40,11 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
index adb1c008e871..2dc7787234c3 100644
--- a/sound/soc/sdw_utils/soc_sdw_cs42l43.c
+++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
@@ -20,6 +20,8 @@
#include <sound/soc-dapm.h>
#include <sound/soc_sdw_utils.h>
+#define CS42L43_SPK_VOLUME_0DB 128 /* 0dB Max */
+
static const struct snd_soc_dapm_route cs42l43_hs_map[] = {
{ "Headphone", NULL, "cs42l43 AMP3_OUT" },
{ "Headphone", NULL, "cs42l43 AMP4_OUT" },
@@ -117,6 +119,14 @@ int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_so
return -ENOMEM;
}
+ ret = snd_soc_limit_volume(card, "cs42l43 Speaker Digital Volume",
+ CS42L43_SPK_VOLUME_0DB);
+ if (ret)
+ dev_err(card->dev, "cs42l43 speaker volume limit failed: %d\n", ret);
+ else
+ dev_info(card->dev, "Setting CS42L43 Speaker volume limit to %d\n",
+ CS42L43_SPK_VOLUME_0DB);
+
ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_spk_map,
ARRAY_SIZE(cs42l43_spk_map));
if (ret)
diff --git a/sound/soc/sdw_utils/soc_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c
index 6951dfb56526..b3d6ca249973 100644
--- a/sound/soc/sdw_utils/soc_sdw_rt_amp.c
+++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c
@@ -190,7 +190,7 @@ int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc
const struct snd_soc_dapm_route *rt_amp_map;
char codec_name[CODEC_NAME_SIZE];
struct snd_soc_dai *codec_dai;
- int ret;
+ int ret = -EINVAL;
int i;
rt_amp_map = get_codec_name_and_route(dai, codec_name);
diff --git a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c
index 7f24806d809d..74bca3d04e4f 100644
--- a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c
+++ b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c
@@ -29,6 +29,8 @@ int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_da
mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "rt715-sdca");
else
mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s", component->name_prefix);
+ if (!mic_name)
+ return -ENOMEM;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s mic:%s", card->components,
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index eca5ce096e54..e3ef9104b411 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1758,20 +1758,6 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
return 1;
}
-int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
-{
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- struct rsnd_priv *priv = rsnd_io_to_priv(io);
- struct device *dev = rsnd_priv_to_dev(priv);
-
- if (!runtime) {
- dev_warn(dev, "Can't update kctrl when idle\n");
- return 0;
- }
-
- return 1;
-}
-
struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
{
cfg->cfg.val = cfg->val;
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 3c164d8e3b16..3f1100b98cdd 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -742,7 +742,6 @@ struct rsnd_kctrl_cfg_s {
#define rsnd_kctrl_vals(x) ((x).val) /* = (x).cfg.val[0] */
int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io);
-int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io);
struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg);
struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg);
int rsnd_kctrl_new(struct rsnd_mod *mod,
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index e7f86db0d94c..7d73b183bda6 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -35,6 +35,7 @@ struct rsnd_src {
struct rsnd_mod *dma;
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
struct rsnd_kctrl_cfg_s sync; /* sync convert */
+ u32 current_sync_rate;
int irq;
};
@@ -100,7 +101,7 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
if (!rsnd_src_sync_is_enabled(mod))
return rsnd_io_converted_rate(io);
- convert_rate = src->sync.val;
+ convert_rate = src->current_sync_rate;
if (!convert_rate)
convert_rate = rsnd_io_converted_rate(io);
@@ -201,13 +202,73 @@ static const u32 chan222222[] = {
static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 fin, fout, new_rate;
+ int inc, cnt, rate;
+ u64 base, val;
+
+ if (!runtime)
+ return;
+
+ if (!rsnd_src_sync_is_enabled(mod))
+ return;
+
+ fin = rsnd_src_get_in_rate(priv, io);
+ fout = rsnd_src_get_out_rate(priv, io);
+
+ new_rate = src->sync.val;
+
+ if (!new_rate)
+ new_rate = fout;
+
+ /* Do nothing if no diff */
+ if (new_rate == src->current_sync_rate)
+ return;
+
+ /*
+ * SRCm_IFSVR::INTIFS can change within 1%
+ * see
+ * SRCm_IFSVR::INTIFS Note
+ */
+ inc = fout / 100;
+ cnt = abs(new_rate - fout) / inc;
+ if (fout > new_rate)
+ inc *= -1;
+
+ /*
+ * After start running SRC, we can update only SRC_IFSVR
+ * for Synchronous Mode
+ */
+ base = (u64)0x0400000 * fin;
+ rate = fout;
+ for (int i = 0; i < cnt; i++) {
+ val = base;
+ rate += inc;
+ do_div(val, rate);
+
+ rsnd_mod_write(mod, SRC_IFSVR, val);
+ }
+ val = base;
+ do_div(val, new_rate);
+
+ rsnd_mod_write(mod, SRC_IFSVR, val);
+
+ /* update current_sync_rate */
+ src->current_sync_rate = new_rate;
+}
+
+static void rsnd_src_init_convert_rate(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
int is_play = rsnd_io_is_play(io);
int use_src = 0;
u32 fin, fout;
- u32 ifscr, fsrate, adinr;
+ u32 ifscr, adinr;
u32 cr, route;
u32 i_busif, o_busif, tmp;
const u32 *bsdsr_table;
@@ -245,26 +306,15 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
adinr = rsnd_get_adinr_bit(mod, io) | chan;
/*
- * SRC_IFSCR / SRC_IFSVR
- */
- ifscr = 0;
- fsrate = 0;
- if (use_src) {
- u64 n;
-
- ifscr = 1;
- n = (u64)0x0400000 * fin;
- do_div(n, fout);
- fsrate = n;
- }
-
- /*
+ * SRC_IFSCR
* SRC_SRCCR / SRC_ROUTE_MODE0
*/
+ ifscr = 0;
cr = 0x00011110;
route = 0x0;
if (use_src) {
route = 0x1;
+ ifscr = 0x1;
if (rsnd_src_sync_is_enabled(mod)) {
cr |= 0x1;
@@ -335,7 +385,6 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */
rsnd_mod_write(mod, SRC_ADINR, adinr);
rsnd_mod_write(mod, SRC_IFSCR, ifscr);
- rsnd_mod_write(mod, SRC_IFSVR, fsrate);
rsnd_mod_write(mod, SRC_SRCCR, cr);
rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);
rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);
@@ -348,6 +397,9 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
+ /* update SRC_IFSVR */
+ rsnd_src_set_convert_rate(io, mod);
+
return;
convert_rate_err:
@@ -467,7 +519,8 @@ static int rsnd_src_init(struct rsnd_mod *mod,
int ret;
/* reset sync convert_rate */
- src->sync.val = 0;
+ src->sync.val =
+ src->current_sync_rate = 0;
ret = rsnd_mod_power_on(mod);
if (ret < 0)
@@ -475,7 +528,7 @@ static int rsnd_src_init(struct rsnd_mod *mod,
rsnd_src_activation(mod);
- rsnd_src_set_convert_rate(io, mod);
+ rsnd_src_init_convert_rate(io, mod);
rsnd_src_status_clear(mod);
@@ -493,7 +546,8 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
rsnd_mod_power_off(mod);
/* reset sync convert_rate */
- src->sync.val = 0;
+ src->sync.val =
+ src->current_sync_rate = 0;
return 0;
}
@@ -531,6 +585,22 @@ static irqreturn_t rsnd_src_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
+static int rsnd_src_kctrl_accept_runtime(struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+
+ if (!runtime) {
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ dev_warn(dev, "\"SRC Out Rate\" can use during running\n");
+
+ return 0;
+ }
+
+ return 1;
+}
+
static int rsnd_src_probe_(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -585,7 +655,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
"SRC Out Rate Switch" :
"SRC In Rate Switch",
rsnd_kctrl_accept_anytime,
- rsnd_src_set_convert_rate,
+ rsnd_src_init_convert_rate,
&src->sen, 1);
if (ret < 0)
return ret;
@@ -594,7 +664,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
rsnd_io_is_play(io) ?
"SRC Out Rate" :
"SRC In Rate",
- rsnd_kctrl_accept_runtime,
+ rsnd_src_kctrl_accept_runtime,
rsnd_src_set_convert_rate,
&src->sync, 192000);
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index b3d4e8ae07ef..0c6424a1fcac 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -336,7 +336,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return 0;
rate_err:
- dev_err(dev, "unsupported clock rate\n");
+ dev_err(dev, "unsupported clock rate (%d)\n", rate);
+
return ret;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 20248a29d167..e3c8d4f20b9c 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3057,7 +3057,7 @@ int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop)
unsigned int i, nb_controls;
int ret;
- if (!of_property_read_bool(dev->of_node, prop))
+ if (!of_property_present(dev->of_node, prop))
return 0;
strings = devm_kcalloc(dev, nb_controls_max,
@@ -3131,23 +3131,17 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
if (rx_mask)
snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
- if (of_property_read_bool(np, "dai-tdm-slot-num")) {
- ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
- if (ret)
- return ret;
-
- if (slots)
- *slots = val;
- }
-
- if (of_property_read_bool(np, "dai-tdm-slot-width")) {
- ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
- if (ret)
- return ret;
+ ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
+ if (ret && ret != -EINVAL)
+ return ret;
+ if (!ret && slots)
+ *slots = val;
- if (slot_width)
- *slot_width = val;
- }
+ ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
+ if (ret && ret != -EINVAL)
+ return ret;
+ if (!ret && slot_width)
+ *slot_width = val;
return 0;
}
@@ -3411,12 +3405,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
* check "[prefix]frame-master"
*/
snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
- bit = of_property_read_bool(np, prop);
+ bit = of_property_present(np, prop);
if (bit && bitclkmaster)
*bitclkmaster = of_parse_phandle(np, prop, 0);
snprintf(prop, sizeof(prop), "%sframe-master", prefix);
- frame = of_property_read_bool(np, prop);
+ frame = of_property_present(np, prop);
if (frame && framemaster)
*framemaster = of_parse_phandle(np, prop, 0);
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 4e08892d24c6..de09d21add45 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -275,10 +275,11 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
if (dai->driver->ops &&
dai->driver->ops->xlate_tdm_slot_mask)
- dai->driver->ops->xlate_tdm_slot_mask(slots,
- &tx_mask, &rx_mask);
+ ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
else
- snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+ ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+ if (ret)
+ goto err;
for_each_pcm_streams(stream)
snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]);
@@ -287,6 +288,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
dai->driver->ops->set_tdm_slot)
ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
+err:
return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 19928f098d8d..fb11003d56cf 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -337,7 +337,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < 0)
return -EINVAL;
val = ucontrol->value.integer.value[0];
- if (mc->platform_max && ((int)val + min) > mc->platform_max)
+ if (mc->platform_max && val > mc->platform_max)
return -EINVAL;
if (val > max - min)
return -EINVAL;
@@ -350,7 +350,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[1] < 0)
return -EINVAL;
val2 = ucontrol->value.integer.value[1];
- if (mc->platform_max && ((int)val2 + min) > mc->platform_max)
+ if (mc->platform_max && val2 > mc->platform_max)
return -EINVAL;
if (val2 > max - min)
return -EINVAL;
@@ -503,17 +503,16 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- int platform_max;
- int min = mc->min;
+ int max;
- if (!mc->platform_max)
- mc->platform_max = mc->max;
- platform_max = mc->platform_max;
+ max = mc->max - mc->min;
+ if (mc->platform_max && mc->platform_max < max)
+ max = mc->platform_max;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = platform_max - min;
+ uinfo->value.integer.max = max;
return 0;
}
@@ -640,6 +639,33 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
+static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ struct snd_ctl_elem_value uctl;
+ int ret;
+
+ if (!mc->platform_max)
+ return 0;
+
+ ret = kctl->get(kctl, &uctl);
+ if (ret < 0)
+ return ret;
+
+ if (uctl.value.integer.value[0] > mc->platform_max)
+ uctl.value.integer.value[0] = mc->platform_max;
+
+ if (snd_soc_volsw_is_stereo(mc) &&
+ uctl.value.integer.value[1] > mc->platform_max)
+ uctl.value.integer.value[1] = mc->platform_max;
+
+ ret = kctl->put(kctl, &uctl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
/**
* snd_soc_limit_volume - Set new limit to an existing volume control.
*
@@ -664,7 +690,7 @@ int snd_soc_limit_volume(struct snd_soc_card *card,
struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
if (max <= mc->max - mc->min) {
mc->platform_max = max;
- ret = 0;
+ ret = snd_soc_clip_to_platform_max(kctl);
}
}
return ret;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 1102599403c5..0e21ff9f7b74 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1633,10 +1633,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
/*
* Filter for systems with 'component_chaining' enabled.
* This helps to avoid unnecessary re-configuration of an
- * already active BE on such systems.
+ * already active BE on such systems and ensures the BE DAI
+ * widget is powered ON after hw_params() BE DAI callback.
*/
if (fe->card->component_chaining &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
continue;
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index b44b1b1adb6e..cf3994a705f9 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -167,6 +167,7 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
if (sdev->first_boot && sdev->fw_state != SOF_FW_BOOT_COMPLETE) {
acp_mailbox_read(sdev, sdev->dsp_box.offset, &status, sizeof(status));
+
if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
snd_sof_dsp_panic(sdev, sdev->dsp_box.offset + sizeof(status),
true);
@@ -188,13 +189,21 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write);
if (dsp_ack) {
- spin_lock_irq(&sdev->ipc_lock);
- /* handle immediate reply from DSP core */
- acp_dsp_ipc_get_reply(sdev);
- snd_sof_ipc_reply(sdev, 0);
- /* set the done bit */
- acp_dsp_ipc_dsp_done(sdev);
- spin_unlock_irq(&sdev->ipc_lock);
+ if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+ spin_lock_irq(&sdev->ipc_lock);
+
+ /* handle immediate reply from DSP core */
+ acp_dsp_ipc_get_reply(sdev);
+ snd_sof_ipc_reply(sdev, 0);
+ /* set the done bit */
+ acp_dsp_ipc_dsp_done(sdev);
+
+ spin_unlock_irq(&sdev->ipc_lock);
+ } else {
+ dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_BOOT_COMPLETE: %#x\n",
+ dsp_ack);
+ }
+
ipc_irq = true;
}
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index 95d4762c9d93..35eb23d2a056 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -27,6 +27,7 @@ MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug");
static struct acp_quirk_entry quirk_valve_galileo = {
.signed_fw_image = true,
.skip_iram_dram_size_mod = true,
+ .post_fw_run_delay = true,
};
const struct dmi_system_id acp_sof_quirk_table[] = {
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 800594440f73..2a19d82d6200 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -220,6 +220,7 @@ struct sof_amd_acp_desc {
struct acp_quirk_entry {
bool signed_fw_image;
bool skip_iram_dram_size_mod;
+ bool post_fw_run_delay;
};
/* Common device data struct for ACP devices */
diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c
index a5d8b6a95a22..fe2ad0395f5d 100644
--- a/sound/soc/sof/amd/pci-acp70.c
+++ b/sound/soc/sof/amd/pci-acp70.c
@@ -34,6 +34,7 @@ static const struct sof_amd_acp_desc acp70_chip_info = {
.ext_intr_cntl = ACP70_EXTERNAL_INTR_CNTL,
.ext_intr_stat = ACP70_EXT_INTR_STAT,
.ext_intr_stat1 = ACP70_EXT_INTR_STAT1,
+ .acp_error_stat = ACP70_ERROR_STATUS,
.dsp_intr_base = ACP70_DSP_SW_INTR_BASE,
.acp_sw0_i2s_err_reason = ACP7X_SW0_I2S_ERROR_REASON,
.sram_pte_offset = ACP70_SRAM_PTE_OFFSET,
diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c
index 61372958c09d..436f58be3a9f 100644
--- a/sound/soc/sof/amd/vangogh.c
+++ b/sound/soc/sof/amd/vangogh.c
@@ -11,6 +11,7 @@
* Hardware interface for Audio DSP on Vangogh platform
*/
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/module.h>
@@ -136,6 +137,20 @@ static struct snd_soc_dai_driver vangogh_sof_dai[] = {
},
};
+static int sof_vangogh_post_fw_run_delay(struct snd_sof_dev *sdev)
+{
+ /*
+ * Resuming from suspend in some cases my cause the DSP firmware
+ * to enter an unrecoverable faulty state. Delaying a bit any host
+ * to DSP transmission right after firmware boot completion seems
+ * to resolve the issue.
+ */
+ if (!sdev->first_boot)
+ usleep_range(100, 150);
+
+ return 0;
+}
+
/* Vangogh ops */
struct snd_sof_dsp_ops sof_vangogh_ops;
EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON);
@@ -157,6 +172,9 @@ int sof_vangogh_ops_init(struct snd_sof_dev *sdev)
if (quirks->signed_fw_image)
sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware;
+
+ if (quirks->post_fw_run_delay)
+ sof_vangogh_ops.post_fw_run = sof_vangogh_post_fw_run_delay;
}
return 0;
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
index 1989147aa6a4..5fe237688b91 100644
--- a/sound/soc/sof/intel/hda-bus.c
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -76,7 +76,7 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops);
- if (chip && chip->hw_ip_version == SOF_INTEL_ACE_2_0)
+ if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0)
bus->use_pio_for_commands = true;
#else
snd_hdac_ext_bus_init(bus, dev, NULL, NULL);
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index dc46888faa0d..c0c58b429715 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -454,6 +454,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
}
EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+MODULE_SOFTDEP("pre: snd-hda-codec-hdmi");
#endif
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index f10ed4d10250..624598c9e2df 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1007,7 +1007,21 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
if (!*mach && codec_num <= 2) {
bool tplg_fixup = false;
- hda_mach = snd_soc_acpi_intel_hda_machines;
+ /*
+ * make a local copy of the match array since we might
+ * be modifying it
+ */
+ hda_mach = devm_kmemdup_array(sdev->dev,
+ snd_soc_acpi_intel_hda_machines,
+ 2, /* we have one entry + sentinel in the array */
+ sizeof(snd_soc_acpi_intel_hda_machines[0]),
+ GFP_KERNEL);
+ if (!hda_mach) {
+ dev_err(bus->dev,
+ "%s: failed to duplicate the HDA match table\n",
+ __func__);
+ return;
+ }
dev_info(bus->dev, "using HDA machine driver %s now\n",
hda_mach->drv_name);
@@ -1195,11 +1209,11 @@ static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach)
return 0;
}
-static char *remove_file_ext(const char *tplg_filename)
+static char *remove_file_ext(struct device *dev, const char *tplg_filename)
{
char *filename, *tmp;
- filename = kstrdup(tplg_filename, GFP_KERNEL);
+ filename = devm_kstrdup(dev, tplg_filename, GFP_KERNEL);
if (!filename)
return NULL;
@@ -1283,7 +1297,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
*/
if (!sof_pdata->tplg_filename) {
/* remove file extension if it exists */
- tplg_filename = remove_file_ext(mach->sof_tplg_filename);
+ tplg_filename = remove_file_ext(sdev->dev, mach->sof_tplg_filename);
if (!tplg_filename)
return NULL;
@@ -1305,22 +1319,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
/* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev);
- if (sdw_mach_found) {
- /*
- * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
- * link 2 and 3, or link 1 and 2, thus we only try to enable dmics
- * if all conditions are true:
- * a) 2 or fewer links are used by SoundWire
- * b) the NHLT table reports the presence of microphones
- */
- if (hweight_long(mach->link_mask) <= 2)
- dmic_fixup = true;
- else
- mach->mach_params.dmic_num = 0;
- } else {
- if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER)
- dmic_fixup = true;
- }
+ if (sdw_mach_found || mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER)
+ dmic_fixup = true;
if (tplg_fixup &&
dmic_fixup &&
diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c
index 69195b5e7b1a..f54d098d616f 100644
--- a/sound/soc/sof/intel/pci-ptl.c
+++ b/sound/soc/sof/intel/pci-ptl.c
@@ -50,6 +50,7 @@ static const struct sof_dev_desc ptl_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_PTL, &ptl_desc) }, /* PTL */
+ { PCI_DEVICE_DATA(INTEL, HDA_PTL_H, &ptl_desc) }, /* PTL-H */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
index 576f407cd456..976a4794d610 100644
--- a/sound/soc/sof/ipc4-control.c
+++ b/sound/soc/sof/ipc4-control.c
@@ -531,6 +531,14 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
return -EINVAL;
}
+ /* Check header id */
+ if (header.numid != SOF_CTRL_CMD_BINARY) {
+ dev_err_ratelimited(scomp->dev,
+ "Incorrect numid for bytes put %d\n",
+ header.numid);
+ return -EINVAL;
+ }
+
/* Verify the ABI header first */
if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr)))
return -EFAULT;
@@ -613,7 +621,8 @@ static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
if (data_size > size)
return -ENOSPC;
- header.numid = scontrol->comp_id;
+ /* Set header id and length */
+ header.numid = SOF_CTRL_CMD_BINARY;
header.length = data_size;
if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 4df2be3d39eb..9db2cdb32128 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -780,7 +780,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm
/* allocate memory for max number of pipeline IDs */
pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines,
- sizeof(struct snd_sof_widget *), GFP_KERNEL);
+ sizeof(*pipeline_list->pipelines),
+ GFP_KERNEL);
if (!pipeline_list->pipelines) {
sof_ipc4_pcm_free(sdev, spcm);
return -ENOMEM;
@@ -794,7 +795,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm
spcm->stream[stream].private = stream_priv;
- if (!support_info)
+ /* Delay reporting is only supported on playback */
+ if (!support_info || stream == SNDRV_PCM_STREAM_CAPTURE)
continue;
time_info = kzalloc(sizeof(*time_info), GFP_KERNEL);
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index b3fca5fd87d6..f9708b8fd73b 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1059,7 +1059,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
struct snd_sof_dai *dai)
{
struct snd_soc_card *card = scomp->card;
- struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_pcm_runtime *rtd, *full, *partial;
struct snd_soc_dai *cpu_dai;
int stream;
int i;
@@ -1076,12 +1076,22 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
else
goto end;
+ full = NULL;
+ partial = NULL;
list_for_each_entry(rtd, &card->rtd_list, list) {
/* does stream match DAI link ? */
- if (!rtd->dai_link->stream_name ||
- !strstr(rtd->dai_link->stream_name, w->sname))
- continue;
+ if (rtd->dai_link->stream_name) {
+ if (!strcmp(rtd->dai_link->stream_name, w->sname)) {
+ full = rtd;
+ break;
+ } else if (strstr(rtd->dai_link->stream_name, w->sname)) {
+ partial = rtd;
+ }
+ }
+ }
+ rtd = full ? full : partial;
+ if (rtd) {
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
/*
* Please create DAI widget in the right order
@@ -1269,8 +1279,8 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
struct snd_sof_tuple *new_tuples;
num_tuples += token_list[object_token_list[i]].count * (num_sets - 1);
- new_tuples = krealloc(swidget->tuples,
- sizeof(*new_tuples) * num_tuples, GFP_KERNEL);
+ new_tuples = krealloc_array(swidget->tuples,
+ num_tuples, sizeof(*new_tuples), GFP_KERNEL);
if (!new_tuples) {
ret = -ENOMEM;
goto err;
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 330bc0c09f56..93dd88fb805d 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -21,6 +21,7 @@
#include <linux/gpio/consumer.h>
#include <sound/core.h>
+#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -235,6 +236,7 @@ struct sun4i_codec {
struct clk *clk_module;
struct reset_control *rst;
struct gpio_desc *gpio_pa;
+ struct gpio_desc *gpio_hp;
/* ADC_FIFOC register is at different offset on different SoCs */
struct regmap_field *reg_adc_fifoc;
@@ -1263,6 +1265,49 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
.ops = &dummy_dai_ops,
};
+static struct snd_soc_jack sun4i_headphone_jack;
+
+static struct snd_soc_jack_pin sun4i_headphone_jack_pins[] = {
+ { .pin = "Headphone", .mask = SND_JACK_HEADPHONE },
+};
+
+static struct snd_soc_jack_gpio sun4i_headphone_jack_gpio = {
+ .name = "hp-det",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+};
+
+static int sun4i_codec_machine_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (scodec->gpio_hp) {
+ ret = snd_soc_card_jack_new_pins(card, "Headphone Jack",
+ SND_JACK_HEADPHONE,
+ &sun4i_headphone_jack,
+ sun4i_headphone_jack_pins,
+ ARRAY_SIZE(sun4i_headphone_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev,
+ "Headphone jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ sun4i_headphone_jack_gpio.desc = scodec->gpio_hp;
+ ret = snd_soc_jack_add_gpios(&sun4i_headphone_jack, 1,
+ &sun4i_headphone_jack_gpio);
+
+ if (ret) {
+ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
int *num_links)
{
@@ -1288,6 +1333,7 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
link->codecs->name = dev_name(dev);
link->platforms->name = dev_name(dev);
link->dai_fmt = SND_SOC_DAIFMT_I2S;
+ link->init = sun4i_codec_machine_init;
*num_links = 1;
@@ -1728,6 +1774,13 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return ret;
}
+ scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN);
+ if (IS_ERR(scodec->gpio_hp)) {
+ ret = PTR_ERR(scodec->gpio_hp);
+ dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n");
+ return ret;
+ }
+
/* reg_field setup */
scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
scodec->regmap,
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
index 1920b996e9aa..51043e556b3e 100644
--- a/sound/soc/tegra/tegra210_ahub.c
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -1359,6 +1359,8 @@ static int tegra_ahub_probe(struct platform_device *pdev)
return -ENOMEM;
ahub->soc_data = of_device_get_match_data(&pdev->dev);
+ if (!ahub->soc_data)
+ return -ENODEV;
platform_set_drvdata(pdev, ahub);
diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c
index d9d1e021f5b2..0f96cc45578d 100644
--- a/sound/soc/ti/j721e-evm.c
+++ b/sound/soc/ti/j721e-evm.c
@@ -182,6 +182,8 @@ static int j721e_configure_refclk(struct j721e_priv *priv,
clk_id = J721E_CLK_PARENT_48000;
else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_44100])
clk_id = J721E_CLK_PARENT_44100;
+ else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_48000])
+ clk_id = J721E_CLK_PARENT_48000;
else
return ret;
diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c
index cf43ac19c4a6..55e7cb96858f 100644
--- a/sound/soc/ti/omap-hdmi.c
+++ b/sound/soc/ti/omap-hdmi.c
@@ -361,17 +361,20 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
if (!card->dai_link)
return -ENOMEM;
- compnent = devm_kzalloc(dev, sizeof(*compnent), GFP_KERNEL);
+ compnent = devm_kzalloc(dev, 2 * sizeof(*compnent), GFP_KERNEL);
if (!compnent)
return -ENOMEM;
- card->dai_link->cpus = compnent;
+ card->dai_link->cpus = &compnent[0];
card->dai_link->num_cpus = 1;
card->dai_link->codecs = &snd_soc_dummy_dlc;
card->dai_link->num_codecs = 1;
+ card->dai_link->platforms = &compnent[1];
+ card->dai_link->num_platforms = 1;
card->dai_link->name = card->name;
card->dai_link->stream_name = card->name;
card->dai_link->cpus->dai_name = dev_name(ad->dssdev);
+ card->dai_link->platforms->name = dev_name(ad->dssdev);
card->num_links = 1;
card->dev = dev;
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index a29f28eb7d0c..f36ec98da460 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -926,6 +926,8 @@ static int endpoint_set_interface(struct snd_usb_audio *chip,
{
int altset = set ? ep->altsetting : 0;
int err;
+ int retries = 0;
+ const int max_retries = 5;
if (ep->iface_ref->altset == altset)
return 0;
@@ -935,8 +937,13 @@ static int endpoint_set_interface(struct snd_usb_audio *chip,
usb_audio_dbg(chip, "Setting usb interface %d:%d for EP 0x%x\n",
ep->iface, altset, ep->ep_num);
+retry:
err = usb_set_interface(chip->dev, ep->iface, altset);
if (err < 0) {
+ if (err == -EPROTO && ++retries <= max_retries) {
+ msleep(5 * (1 << (retries - 1)));
+ goto retry;
+ }
usb_audio_err_ratelimited(
chip, "%d:%d: usb_set_interface failed (%d)\n",
ep->iface, altset, err);
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 6049d957694c..a9283b2bd2f4 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -260,7 +260,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
}
/* Jabra Evolve 65 headset */
- if (chip->usb_id == USB_ID(0x0b0e, 0x030b)) {
+ if (chip->usb_id == USB_ID(0x0b0e, 0x030b) ||
+ chip->usb_id == USB_ID(0x0b0e, 0x030c)) {
/* only 48kHz for playback while keeping 16kHz for capture */
if (fp->nr_rates != 1)
return set_fixed_rate(fp, 48000, SNDRV_PCM_RATE_48000);
diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c
index 4727043fd745..77f06da93151 100644
--- a/sound/usb/implicit.c
+++ b/sound/usb/implicit.c
@@ -57,6 +57,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */
IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */
IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */
+ IMPLICIT_FB_FIXED_DEV(0x19f7, 0x000a, 0x84, 3), /* RODE AI-1 */
IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */
IMPLICIT_FB_FIXED_DEV(0x1686, 0xf029, 0x82, 2), /* Zoom UAC-2 */
IMPLICIT_FB_FIXED_DEV(0x2466, 0x8003, 0x86, 2), /* Fractal Audio Axe-Fx II */
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 779d97d31f17..a792ada18863 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -489,16 +489,84 @@ static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
/*
* CME protocol: like the standard protocol, but SysEx commands are sent as a
- * single USB packet preceded by a 0x0F byte.
+ * single USB packet preceded by a 0x0F byte, as are system realtime
+ * messages and MIDI Active Sensing.
+ * Also, multiple messages can be sent in the same packet.
*/
static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep,
uint8_t *buffer, int buffer_length)
{
- if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f)
- snd_usbmidi_standard_input(ep, buffer, buffer_length);
- else
- snd_usbmidi_input_data(ep, buffer[0] >> 4,
- &buffer[1], buffer_length - 1);
+ int remaining = buffer_length;
+
+ /*
+ * CME send sysex, song position pointer, system realtime
+ * and active sensing using CIN 0x0f, which in the standard
+ * is only intended for single byte unparsed data.
+ * So we need to interpret these here before sending them on.
+ * By default, we assume single byte data, which is true
+ * for system realtime (midi clock, start, stop and continue)
+ * and active sensing, and handle the other (known) cases
+ * separately.
+ * In contrast to the standard, CME does not split sysex
+ * into multiple 4-byte packets, but lumps everything together
+ * into one. In addition, CME can string multiple messages
+ * together in the same packet; pressing the Record button
+ * on an UF6 sends a sysex message directly followed
+ * by a song position pointer in the same packet.
+ * For it to have any reasonable meaning, a sysex message
+ * needs to be at least 3 bytes in length (0xf0, id, 0xf7),
+ * corresponding to a packet size of 4 bytes, and the ones sent
+ * by CME devices are 6 or 7 bytes, making the packet fragments
+ * 7 or 8 bytes long (six or seven bytes plus preceding CN+CIN byte).
+ * For the other types, the packet size is always 4 bytes,
+ * as per the standard, with the data size being 3 for SPP
+ * and 1 for the others.
+ * Thus all packet fragments are at least 4 bytes long, so we can
+ * skip anything that is shorter; this also conveniantly skips
+ * packets with size 0, which CME devices continuously send when
+ * they have nothing better to do.
+ * Another quirk is that sometimes multiple messages are sent
+ * in the same packet. This has been observed for midi clock
+ * and active sensing i.e. 0x0f 0xf8 0x00 0x00 0x0f 0xfe 0x00 0x00,
+ * but also multiple note ons/offs, and control change together
+ * with MIDI clock. Similarly, some sysex messages are followed by
+ * the song position pointer in the same packet, and occasionally
+ * additionally by a midi clock or active sensing.
+ * We handle this by looping over all data and parsing it along the way.
+ */
+ while (remaining >= 4) {
+ int source_length = 4; /* default */
+
+ if ((buffer[0] & 0x0f) == 0x0f) {
+ int data_length = 1; /* default */
+
+ if (buffer[1] == 0xf0) {
+ /* Sysex: Find EOX and send on whole message. */
+ /* To kick off the search, skip the first
+ * two bytes (CN+CIN and SYSEX (0xf0).
+ */
+ uint8_t *tmp_buf = buffer + 2;
+ int tmp_length = remaining - 2;
+
+ while (tmp_length > 1 && *tmp_buf != 0xf7) {
+ tmp_buf++;
+ tmp_length--;
+ }
+ data_length = tmp_buf - buffer;
+ source_length = data_length + 1;
+ } else if (buffer[1] == 0xf2) {
+ /* Three byte song position pointer */
+ data_length = 3;
+ }
+ snd_usbmidi_input_data(ep, buffer[0] >> 4,
+ &buffer[1], data_length);
+ } else {
+ /* normal channel events */
+ snd_usbmidi_standard_input(ep, buffer, source_length);
+ }
+ buffer += source_length;
+ remaining -= source_length;
+ }
}
/*
@@ -1817,10 +1885,18 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
}
port_info = find_port_info(umidi, number);
- name_format = port_info ? port_info->name :
- (jack_name != default_jack_name ? "%s %s" : "%s %s %d");
- snprintf(substream->name, sizeof(substream->name),
- name_format, umidi->card->shortname, jack_name, number + 1);
+ if (port_info || jack_name == default_jack_name ||
+ strncmp(umidi->card->shortname, jack_name, strlen(umidi->card->shortname)) != 0) {
+ name_format = port_info ? port_info->name :
+ (jack_name != default_jack_name ? "%s %s" : "%s %s %d");
+ snprintf(substream->name, sizeof(substream->name),
+ name_format, umidi->card->shortname, jack_name, number + 1);
+ } else {
+ /* The manufacturer included the iProduct name in the jack
+ * name, do not use both
+ */
+ strscpy(substream->name, jack_name);
+ }
*rsubstream = substream;
}
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index 0e9b5431a47f..faac7df1fbcf 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -383,6 +383,13 @@ static const struct usbmix_name_map ms_usb_link_map[] = {
{ 0 } /* terminator */
};
+/* KTMicro USB */
+static struct usbmix_name_map s31b2_0022_map[] = {
+ { 23, "Speaker Playback" },
+ { 18, "Headphone Playback" },
+ { 0 }
+};
+
/* ASUS ROG Zenith II with Realtek ALC1220-VB */
static const struct usbmix_name_map asus_zenith_ii_map[] = {
{ 19, NULL, 12 }, /* FU, Input Gain Pad - broken response, disabled */
@@ -692,6 +699,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
.id = USB_ID(0x045e, 0x083c),
.map = ms_usb_link_map,
},
+ {
+ /* KTMicro USB */
+ .id = USB_ID(0X31b2, 0x0022),
+ .map = s31b2_0022_map,
+ },
{ 0 } /* terminator */
};
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index a95ebcf4e46e..1e7192cb4693 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -4156,6 +4156,52 @@ static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer,
}
}
+/*
+ * Some Plantronics headsets have control names that don't meet ALSA naming
+ * standards. This function fixes nonstandard source names. By the time
+ * this function is called the control name should look like one of these:
+ * "source names Playback Volume"
+ * "source names Playback Switch"
+ * "source names Capture Volume"
+ * "source names Capture Switch"
+ * If any of the trigger words are found in the name then the name will
+ * be changed to:
+ * "Headset Playback Volume"
+ * "Headset Playback Switch"
+ * "Headset Capture Volume"
+ * "Headset Capture Switch"
+ * depending on the current suffix.
+ */
+static void snd_fix_plt_name(struct snd_usb_audio *chip,
+ struct snd_ctl_elem_id *id)
+{
+ /* no variant of "Sidetone" should be added to this list */
+ static const char * const trigger[] = {
+ "Earphone", "Microphone", "Receive", "Transmit"
+ };
+ static const char * const suffix[] = {
+ " Playback Volume", " Playback Switch",
+ " Capture Volume", " Capture Switch"
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(trigger); i++)
+ if (strstr(id->name, trigger[i]))
+ goto triggered;
+ usb_audio_dbg(chip, "no change in %s\n", id->name);
+ return;
+
+triggered:
+ for (i = 0; i < ARRAY_SIZE(suffix); i++)
+ if (strstr(id->name, suffix[i])) {
+ usb_audio_dbg(chip, "fixing kctl name %s\n", id->name);
+ snprintf(id->name, sizeof(id->name), "Headset%s",
+ suffix[i]);
+ return;
+ }
+ usb_audio_dbg(chip, "something wrong in kctl name %s\n", id->name);
+}
+
void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
struct usb_mixer_elem_info *cval, int unitid,
struct snd_kcontrol *kctl)
@@ -4173,5 +4219,10 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
cval->min_mute = 1;
break;
}
+
+ /* ALSA-ify some Plantronics headset control names */
+ if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f &&
+ (cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME))
+ snd_fix_plt_name(mixer->chip, &kctl->id);
}
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 09210fb4ac60..0da4ee9757c0 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2240,6 +2240,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */
QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x0c45, 0x636b, /* Microdia JP001 USB Camera */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x0d8c, 0x0014, /* USB Audio Device */
QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
@@ -2248,6 +2250,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_FIXED_RATE),
DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
@@ -2278,6 +2282,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_DISABLE_AUTOSUSPEND),
DEVICE_FLG(0x17aa, 0x104d, /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */
QUIRK_FLAG_DISABLE_AUTOSUSPEND),
+ DEVICE_FLG(0x17ef, 0x3083, /* Lenovo TBT3 dock */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x1852, 0x5062, /* Luxman D-08u */
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
DEVICE_FLG(0x1852, 0x5065, /* Luxman DA-06 */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index c1ea8844a46f..aa91d63749f2 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -987,6 +987,8 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
* and request Cluster Descriptor
*/
wLength = le16_to_cpu(hc_header.wLength);
+ if (wLength < sizeof(cluster))
+ return NULL;
cluster = kzalloc(wLength, GFP_KERNEL);
if (!cluster)
return ERR_PTR(-ENOMEM);
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 5f81c68fd42b..5756ff3528a2 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -151,6 +151,12 @@ static int snd_usx2y_card_used[SNDRV_CARDS];
static void snd_usx2y_card_private_free(struct snd_card *card);
static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s);
+#ifdef USX2Y_NRPACKS_VARIABLE
+int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
+module_param(nrpacks, int, 0444);
+MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
+#endif
+
/*
* pipe 4 is used for switching the lamps, setting samplerate, volumes ....
*/
@@ -432,6 +438,11 @@ static int snd_usx2y_probe(struct usb_interface *intf,
struct snd_card *card;
int err;
+#ifdef USX2Y_NRPACKS_VARIABLE
+ if (nrpacks < 0 || nrpacks > USX2Y_NRPACKS_MAX)
+ return -EINVAL;
+#endif
+
if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 ||
(le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 &&
le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 &&
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
index 391fd7b4ed5e..6a76d04bf1c7 100644
--- a/sound/usb/usx2y/usbusx2y.h
+++ b/sound/usb/usx2y/usbusx2y.h
@@ -7,6 +7,32 @@
#define NRURBS 2
+/* Default value used for nr of packs per urb.
+ * 1 to 4 have been tested ok on uhci.
+ * To use 3 on ohci, you'd need a patch:
+ * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
+ * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
+ *
+ * 1, 2 and 4 work out of the box on ohci, if I recall correctly.
+ * Bigger is safer operation, smaller gives lower latencies.
+ */
+#define USX2Y_NRPACKS 4
+
+#define USX2Y_NRPACKS_MAX 1024
+
+/* If your system works ok with this module's parameter
+ * nrpacks set to 1, you might as well comment
+ * this define out, and thereby produce smaller, faster code.
+ * You'd also set USX2Y_NRPACKS to 1 then.
+ */
+#define USX2Y_NRPACKS_VARIABLE 1
+
+#ifdef USX2Y_NRPACKS_VARIABLE
+extern int nrpacks;
+#define nr_of_packs() nrpacks
+#else
+#define nr_of_packs() USX2Y_NRPACKS
+#endif
#define URBS_ASYNC_SEQ 10
#define URB_DATA_LEN_ASYNC_SEQ 32
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index f540f46a0b14..acca8bead82e 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -28,33 +28,6 @@
#include "usx2y.h"
#include "usbusx2y.h"
-/* Default value used for nr of packs per urb.
- * 1 to 4 have been tested ok on uhci.
- * To use 3 on ohci, you'd need a patch:
- * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
- * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
- *
- * 1, 2 and 4 work out of the box on ohci, if I recall correctly.
- * Bigger is safer operation, smaller gives lower latencies.
- */
-#define USX2Y_NRPACKS 4
-
-/* If your system works ok with this module's parameter
- * nrpacks set to 1, you might as well comment
- * this define out, and thereby produce smaller, faster code.
- * You'd also set USX2Y_NRPACKS to 1 then.
- */
-#define USX2Y_NRPACKS_VARIABLE 1
-
-#ifdef USX2Y_NRPACKS_VARIABLE
-static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
-#define nr_of_packs() nrpacks
-module_param(nrpacks, int, 0444);
-MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
-#else
-#define nr_of_packs() USX2Y_NRPACKS
-#endif
-
static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs)
{
struct urb *urb = subs->completed_urb;
diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
index 967e4c45be9b..2f7c5e709f07 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -339,6 +339,21 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
if (!snd->substreams)
return -ENOMEM;
+ /*
+ * Initialize critical substream fields early in case we hit an
+ * error path and end up trying to clean up uninitialized structures
+ * elsewhere.
+ */
+ for (i = 0; i < snd->nsubstreams; ++i) {
+ struct virtio_pcm_substream *vss = &snd->substreams[i];
+
+ vss->snd = snd;
+ vss->sid = i;
+ INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed);
+ init_waitqueue_head(&vss->msg_empty);
+ spin_lock_init(&vss->lock);
+ }
+
info = kcalloc(snd->nsubstreams, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -352,12 +367,6 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
struct virtio_pcm_substream *vss = &snd->substreams[i];
struct virtio_pcm *vpcm;
- vss->snd = snd;
- vss->sid = i;
- INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed);
- init_waitqueue_head(&vss->msg_empty);
- spin_lock_init(&vss->lock);
-
rc = virtsnd_pcm_build_hw(vss, &info[i]);
if (rc)
goto on_exit;