summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/misc.c8
-rw-r--r--sound/core/oss/pcm_oss.c29
-rw-r--r--sound/core/pcm_drm_eld.c4
-rw-r--r--sound/core/pcm_lib.c3
-rw-r--r--sound/core/seq/seq_clientmgr.c2
-rw-r--r--sound/core/seq/seq_clientmgr.h5
-rw-r--r--sound/core/seq/seq_ports.c7
-rw-r--r--sound/core/seq/seq_ump_client.c24
-rw-r--r--sound/core/timer.c19
-rw-r--r--sound/drivers/aloop.c43
-rw-r--r--sound/drivers/pcmtest.c6
-rw-r--r--sound/firewire/tascam/tascam-hwdep.c1
-rw-r--r--sound/hda/codecs/Makefile2
-rw-r--r--sound/hda/codecs/ca0132.c44
-rw-r--r--sound/hda/codecs/conexant.c8
-rw-r--r--sound/hda/codecs/realtek/alc269.c101
-rw-r--r--sound/hda/codecs/side-codecs/Kconfig1
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda.c4
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda.c32
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda.h1
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_spi.c14
-rw-r--r--sound/hda/common/auto_parser.c4
-rw-r--r--sound/hda/common/codec.c3
-rw-r--r--sound/hda/common/controller.c28
-rw-r--r--sound/hda/common/hda_controller.h14
-rw-r--r--sound/hda/controllers/intel.c106
-rw-r--r--sound/hda/controllers/intel.h15
-rw-r--r--sound/hda/core/hdmi_chmap.c11
-rw-r--r--sound/pci/asihpi/hpicmn.c6
-rw-r--r--sound/soc/amd/acp-config.c7
-rw-r--r--sound/soc/amd/acp/acp-legacy-mach.c2
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c22
-rw-r--r--sound/soc/amd/acp/acp-mach.h4
-rw-r--r--sound/soc/amd/acp/acp-sdw-legacy-mach.c2
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c2
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c21
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/ab8500-codec.c304
-rw-r--r--sound/soc/codecs/aw88395/aw88395.c9
-rw-r--r--sound/soc/codecs/cs-amp-lib.c17
-rw-r--r--sound/soc/codecs/cs35l56-sdw.c8
-rw-r--r--sound/soc/codecs/cs35l56-shared.c18
-rw-r--r--sound/soc/codecs/cs35l56.c24
-rw-r--r--sound/soc/codecs/es8389.c2
-rw-r--r--sound/soc/codecs/fs210x.c2
-rw-r--r--sound/soc/codecs/pcm512x.c6
-rw-r--r--sound/soc/codecs/tas2764.c36
-rw-r--r--sound/soc/codecs/tas2770.c27
-rw-r--r--sound/soc/codecs/wcd937x.c26
-rw-r--r--sound/soc/codecs/wm_adsp_fw_find_test.c57
-rw-r--r--sound/soc/fsl/fsl_sai.c43
-rw-r--r--sound/soc/fsl/fsl_xcvr.c17
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c1
-rw-r--r--sound/soc/intel/boards/sof_sdw.c8
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-arl-match.c71
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-nvl-match.c13
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ptl-match.c134
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c16
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h1
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-dai.c7
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c15
-rw-r--r--sound/soc/soc-utils.c1
-rw-r--r--sound/soc/sof/amd/acp.c2
-rw-r--r--sound/soc/sof/intel/hda.c3
-rw-r--r--sound/soc/spacemit/k1_i2s.c56
-rw-r--r--sound/soc/tegra/Makefile1
-rw-r--r--sound/soc/ti/omap-dmic.c2
-rw-r--r--sound/sparc/dbri.c1
-rw-r--r--sound/usb/caiaq/device.c6
-rw-r--r--sound/usb/caiaq/input.c2
-rw-r--r--sound/usb/clock.c15
-rw-r--r--sound/usb/midi.c12
-rw-r--r--sound/usb/midi2.c21
-rw-r--r--sound/usb/misc/ua101.c12
-rw-r--r--sound/usb/mixer.c10
-rw-r--r--sound/usb/mixer_scarlett2.c9
-rw-r--r--sound/usb/qcom/qc_audio_offload.c31
-rw-r--r--sound/usb/quirks-table.h4
-rw-r--r--sound/usb/quirks.c11
-rw-r--r--sound/usb/stream.c62
-rw-r--r--sound/usb/stream.h3
81 files changed, 982 insertions, 752 deletions
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 5aca09edf971..833124c8e4fa 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -148,9 +148,11 @@ EXPORT_SYMBOL_GPL(snd_fasync_helper);
void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll)
{
- if (!fasync || !fasync->on)
+ if (!fasync)
return;
guard(spinlock_irqsave)(&snd_fasync_lock);
+ if (!fasync->on)
+ return;
fasync->signal = signal;
fasync->poll = poll;
list_move(&fasync->list, &snd_fasync_list);
@@ -163,8 +165,10 @@ void snd_fasync_free(struct snd_fasync *fasync)
if (!fasync)
return;
- scoped_guard(spinlock_irq, &snd_fasync_lock)
+ scoped_guard(spinlock_irq, &snd_fasync_lock) {
+ fasync->on = 0;
list_del_init(&fasync->list);
+ }
flush_work(&snd_fasync_work);
kfree(fasync);
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index a140a0d9abb8..33fd34f0d615 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2155,10 +2155,16 @@ static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file)
psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
- if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger)
- result |= PCM_ENABLE_OUTPUT;
- if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger)
- result |= PCM_ENABLE_INPUT;
+ if (psubstream && psubstream->runtime) {
+ guard(mutex)(&psubstream->runtime->oss.params_lock);
+ if (psubstream->runtime->oss.trigger)
+ result |= PCM_ENABLE_OUTPUT;
+ }
+ if (csubstream && csubstream->runtime) {
+ guard(mutex)(&csubstream->runtime->oss.params_lock);
+ if (csubstream->runtime->oss.trigger)
+ result |= PCM_ENABLE_INPUT;
+ }
return result;
}
@@ -2832,6 +2838,17 @@ static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
runtime->oss.period_frames;
}
+static bool need_input_retrigger(struct snd_pcm_runtime *runtime)
+{
+ bool ret;
+
+ guard(mutex)(&runtime->oss.params_lock);
+ ret = runtime->oss.trigger;
+ if (ret)
+ runtime->oss.trigger = 0;
+ return ret;
+}
+
static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
{
struct snd_pcm_oss_file *pcm_oss_file;
@@ -2864,11 +2881,11 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
snd_pcm_oss_capture_ready(csubstream))
mask |= EPOLLIN | EPOLLRDNORM;
}
- if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
+ if (ostate != SNDRV_PCM_STATE_RUNNING &&
+ need_input_retrigger(runtime)) {
struct snd_pcm_oss_file ofile;
memset(&ofile, 0, sizeof(ofile));
ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
- runtime->oss.trigger = 0;
snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT);
}
}
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c
index cb2eebaac85f..1941ee520063 100644
--- a/sound/core/pcm_drm_eld.c
+++ b/sound/core/pcm_drm_eld.c
@@ -334,7 +334,7 @@ int snd_parse_eld(struct device *dev, struct snd_parsed_hdmi_eld *e,
e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
if (e->eld_ver != ELD_VER_CEA_861D &&
e->eld_ver != ELD_VER_PARTIAL) {
- dev_info(dev, "HDMI: Unknown ELD version %d\n", e->eld_ver);
+ dev_info_ratelimited(dev, "HDMI: Unknown ELD version %d\n", e->eld_ver);
goto out_fail;
}
@@ -357,7 +357,7 @@ int snd_parse_eld(struct device *dev, struct snd_parsed_hdmi_eld *e,
e->product_id = get_unaligned_le16(buf + 18);
if (mnl > ELD_MAX_MNL) {
- dev_info(dev, "HDMI: MNL is reserved value %d\n", mnl);
+ dev_info_ratelimited(dev, "HDMI: MNL is reserved value %d\n", mnl);
goto out_fail;
} else if (ELD_FIXED_BYTES + mnl > size) {
dev_info(dev, "HDMI: out of range MNL %d\n", mnl);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 09c421cd9319..fe597f7d522d 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -2138,6 +2138,9 @@ static int interleaved_copy(struct snd_pcm_substream *substream,
off = frames_to_bytes(runtime, off);
frames = frames_to_bytes(runtime, frames);
+ if (!data)
+ return fill_silence(substream, 0, hwoff, NULL, frames);
+
return do_transfer(substream, 0, hwoff, data + off, frames, transfer,
in_kernel);
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 75a7a2af9d8c..5719637575a9 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1253,7 +1253,7 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client,
if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3))
client->midi_version = client_info->midi_version;
memcpy(client->event_filter, client_info->event_filter, 32);
- client->group_filter = client_info->group_filter;
+ client->group_filter = client_info->group_filter & SND_SEQ_GROUP_FILTER_MASK;
/* notify the change */
snd_seq_system_client_ev_client_change(client->number);
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index ece02c58db70..feea8bb7d987 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -14,6 +14,9 @@
/* client manager */
+#define SND_SEQ_GROUP_FILTER_MASK GENMASK(SNDRV_UMP_MAX_GROUPS, 0)
+#define SND_SEQ_GROUP_FILTER_GROUPS GENMASK(SNDRV_UMP_MAX_GROUPS, 1)
+
struct snd_seq_user_client {
struct file *file; /* file struct of client */
/* ... */
@@ -40,7 +43,7 @@ struct snd_seq_client {
int number; /* client number */
unsigned int filter; /* filter flags */
DECLARE_BITMAP(event_filter, 256);
- unsigned short group_filter;
+ unsigned int group_filter;
snd_use_lock_t use_lock;
int event_lost;
/* ports */
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index da8d358958f1..31ab4681c601 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -144,18 +144,21 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
num = max(port, 0);
guard(mutex)(&client->ports_mutex);
guard(write_lock_irq)(&client->ports_lock);
+ struct list_head *insert_before = &client->ports_list_head;
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
kfree(new_port);
return -EBUSY;
}
- if (p->addr.port > num)
+ if (p->addr.port > num) {
+ insert_before = &p->list;
break;
+ }
if (port < 0) /* auto-probe mode */
num = p->addr.port + 1;
}
/* insert the new port */
- list_add_tail(&new_port->list, &p->list);
+ list_add_tail(&new_port->list, insert_before);
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c
index fdc76f23e03f..ccd93599b493 100644
--- a/sound/core/seq/seq_ump_client.c
+++ b/sound/core/seq/seq_ump_client.c
@@ -37,6 +37,7 @@ struct seq_ump_client {
struct snd_ump_endpoint *ump; /* assigned endpoint */
int seq_client; /* sequencer client id */
int opened[2]; /* current opens for each direction */
+ rwlock_t output_lock; /* protects out_rfile output access */
struct snd_rawmidi_file out_rfile; /* rawmidi for output */
struct seq_ump_input_buffer input; /* input parser context */
void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
@@ -88,6 +89,7 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
unsigned char type;
int len;
+ guard(read_lock_irqsave)(&client->output_lock);
substream = client->out_rfile.output;
if (!substream)
return -ENODEV;
@@ -106,6 +108,7 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
static int seq_ump_client_open(struct seq_ump_client *client, int dir)
{
struct snd_ump_endpoint *ump = client->ump;
+ struct snd_rawmidi_file rfile = {};
int err;
guard(mutex)(&ump->open_mutex);
@@ -113,9 +116,11 @@ static int seq_ump_client_open(struct seq_ump_client *client, int dir)
err = snd_rawmidi_kernel_open(&ump->core, 0,
SNDRV_RAWMIDI_LFLG_OUTPUT |
SNDRV_RAWMIDI_LFLG_APPEND,
- &client->out_rfile);
+ &rfile);
if (err < 0)
return err;
+ scoped_guard(write_lock_irqsave, &client->output_lock)
+ client->out_rfile = rfile;
}
client->opened[dir]++;
return 0;
@@ -125,11 +130,19 @@ static int seq_ump_client_open(struct seq_ump_client *client, int dir)
static int seq_ump_client_close(struct seq_ump_client *client, int dir)
{
struct snd_ump_endpoint *ump = client->ump;
+ struct snd_rawmidi_file rfile = {};
guard(mutex)(&ump->open_mutex);
- if (!--client->opened[dir])
- if (dir == STR_OUT)
- snd_rawmidi_kernel_release(&client->out_rfile);
+ if (!--client->opened[dir]) {
+ if (dir == STR_OUT) {
+ scoped_guard(write_lock_irqsave, &client->output_lock) {
+ rfile = client->out_rfile;
+ client->out_rfile = (struct snd_rawmidi_file){};
+ }
+ if (rfile.rmidi)
+ snd_rawmidi_kernel_release(&rfile);
+ }
+ }
return 0;
}
@@ -369,7 +382,7 @@ static void setup_client_group_filter(struct seq_ump_client *client)
cptr = snd_seq_kernel_client_get(client->seq_client);
if (!cptr)
return;
- filter = ~(1U << 0); /* always allow groupless messages */
+ filter = SND_SEQ_GROUP_FILTER_GROUPS; /* always allow groupless messages */
for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
if (client->ump->groups[p].active)
filter &= ~(1U << (p + 1));
@@ -467,6 +480,7 @@ static int snd_seq_ump_probe(struct snd_seq_device *dev)
INIT_WORK(&client->group_notify_work, handle_group_notify);
client->ump = ump;
+ rwlock_init(&client->output_lock);
client->seq_client =
snd_seq_create_kernel_client(card, ump->core.device,
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 820901d503af..57583dec3974 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1007,6 +1007,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
{
struct snd_timer *timer = dev->device_data;
struct snd_timer *timer1;
+ struct list_head *insert_before = &snd_timer_list;
if (snd_BUG_ON(!timer || !timer->hw.start || !timer->hw.stop))
return -ENXIO;
@@ -1016,28 +1017,36 @@ static int snd_timer_dev_register(struct snd_device *dev)
guard(mutex)(&register_mutex);
list_for_each_entry(timer1, &snd_timer_list, device_list) {
- if (timer1->tmr_class > timer->tmr_class)
+ if (timer1->tmr_class > timer->tmr_class) {
+ insert_before = &timer1->device_list;
break;
+ }
if (timer1->tmr_class < timer->tmr_class)
continue;
if (timer1->card && timer->card) {
- if (timer1->card->number > timer->card->number)
+ if (timer1->card->number > timer->card->number) {
+ insert_before = &timer1->device_list;
break;
+ }
if (timer1->card->number < timer->card->number)
continue;
}
- if (timer1->tmr_device > timer->tmr_device)
+ if (timer1->tmr_device > timer->tmr_device) {
+ insert_before = &timer1->device_list;
break;
+ }
if (timer1->tmr_device < timer->tmr_device)
continue;
- if (timer1->tmr_subdevice > timer->tmr_subdevice)
+ if (timer1->tmr_subdevice > timer->tmr_subdevice) {
+ insert_before = &timer1->device_list;
break;
+ }
if (timer1->tmr_subdevice < timer->tmr_subdevice)
continue;
/* conflicts.. */
return -EBUSY;
}
- list_add_tail(&timer->device_list, &timer1->device_list);
+ list_add_tail(&timer->device_list, insert_before);
return 0;
}
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index aa0d2fcb1a18..a37a1695f51c 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -99,6 +99,9 @@ struct loopback_ops {
struct loopback_cable {
spinlock_t lock;
struct loopback_pcm *streams[2];
+ /* in-flight peer stops running outside cable->lock */
+ atomic_t stop_count;
+ wait_queue_head_t stop_wait;
struct snd_pcm_hardware hw;
/* flags */
unsigned int valid;
@@ -366,8 +369,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
return 0;
if (stream == SNDRV_PCM_STREAM_CAPTURE)
return -EIO;
- else if (cruntime->state == SNDRV_PCM_STATE_RUNNING)
+ else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) {
+ /* close must not free the peer runtime below */
+ atomic_inc(&cable->stop_count);
stop_capture = true;
+ }
}
setup = get_setup(dpcm_play);
@@ -396,8 +402,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
}
}
- if (stop_capture)
+ if (stop_capture) {
snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING);
+ if (atomic_dec_and_test(&cable->stop_count))
+ wake_up(&cable->stop_wait);
+ }
return 0;
}
@@ -1049,23 +1058,29 @@ static void free_cable(struct snd_pcm_substream *substream)
struct loopback *loopback = substream->private_data;
int dev = get_cable_index(substream);
struct loopback_cable *cable;
+ struct loopback_pcm *dpcm;
+ bool other_alive;
cable = loopback->cables[substream->number][dev];
if (!cable)
return;
- if (cable->streams[!substream->stream]) {
- /* other stream is still alive */
- guard(spinlock_irq)(&cable->lock);
- cable->streams[substream->stream] = NULL;
- } else {
- struct loopback_pcm *dpcm = substream->runtime->private_data;
- if (cable->ops && cable->ops->close_cable && dpcm)
- cable->ops->close_cable(dpcm);
- /* free the cable */
- loopback->cables[substream->number][dev] = NULL;
- kfree(cable);
+ scoped_guard(spinlock_irq, &cable->lock) {
+ cable->streams[substream->stream] = NULL;
+ other_alive = cable->streams[!substream->stream];
}
+
+ /* Pair with the stop_count increment in loopback_check_format(). */
+ wait_event(cable->stop_wait, !atomic_read(&cable->stop_count));
+ if (other_alive)
+ return;
+
+ dpcm = substream->runtime->private_data;
+ if (cable->ops && cable->ops->close_cable && dpcm)
+ cable->ops->close_cable(dpcm);
+ /* free the cable */
+ loopback->cables[substream->number][dev] = NULL;
+ kfree(cable);
}
static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm)
@@ -1260,6 +1275,8 @@ static int loopback_open(struct snd_pcm_substream *substream)
goto unlock;
}
spin_lock_init(&cable->lock);
+ atomic_set(&cable->stop_count, 0);
+ init_waitqueue_head(&cable->stop_wait);
cable->hw = loopback_pcm_hardware;
if (loopback->timer_source)
cable->ops = &loopback_snd_timer_ops;
diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c
index 5bfec4c7bf71..7f93557b51ec 100644
--- a/sound/drivers/pcmtest.c
+++ b/sound/drivers/pcmtest.c
@@ -679,9 +679,9 @@ static ssize_t pattern_read(struct file *file, char __user *u_buff, size_t len,
return 0;
if (copy_to_user(u_buff, patt_buf->buf + *off, to_read))
- to_read = 0;
- else
- *off += to_read;
+ return -EFAULT;
+
+ *off += to_read;
return to_read;
}
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
index 867b4ea1096e..6270263e7bf4 100644
--- a/sound/firewire/tascam/tascam-hwdep.c
+++ b/sound/firewire/tascam/tascam-hwdep.c
@@ -73,6 +73,7 @@ static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
length = rounddown(remained, sizeof(*entries));
if (length == 0)
break;
+ tail_pos = head_pos + length / sizeof(*entries);
spin_unlock_irq(&tscm->lock);
if (copy_to_user(pos, &entries[head_pos], length))
diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile
index e7f03e281999..88d2f8a79467 100644
--- a/sound/hda/codecs/Makefile
+++ b/sound/hda/codecs/Makefile
@@ -7,7 +7,6 @@ snd-hda-codec-cm9825-y := cm9825.o
snd-hda-codec-analog-y := analog.o
snd-hda-codec-ca0110-y := ca0110.o
snd-hda-codec-ca0132-y := ca0132.o
-snd-hda-codec-cmedia-y := cmedia.o
snd-hda-codec-conexant-y := conexant.o
snd-hda-codec-idt-y := sigmatel.o
snd-hda-codec-senarytech-y := senarytech.o
@@ -26,7 +25,6 @@ obj-$(CONFIG_SND_HDA_CODEC_CM9825) += snd-hda-codec-cm9825.o
obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
-obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c
index ad533b04ab29..be565ffaade0 100644
--- a/sound/hda/codecs/ca0132.c
+++ b/sound/hda/codecs/ca0132.c
@@ -5498,6 +5498,30 @@ static int zxr_headphone_gain_set(struct hda_codec *codec, long val)
return 0;
}
+/*
+ * Manual output selection (HP/Speaker Playback Switch or alt Output Select)
+ * is meaningful only when HP/Speaker auto-detect is disabled, since the
+ * select_out path always prefers jack presence when auto-detect is on. When
+ * the user explicitly chooses an output, turn auto-detect off so the manual
+ * choice actually takes effect, and notify userspace so the auto-detect
+ * control reflects the new state.
+ */
+static void ca0132_disable_hp_auto_detect(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+ struct snd_kcontrol *kctl;
+
+ if (!spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID])
+ return;
+
+ spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID] = 0;
+ kctl = snd_hda_find_mixer_ctl(codec,
+ "HP/Speaker Auto Detect Playback Switch");
+ if (kctl)
+ snd_ctl_notify(codec->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &kctl->id);
+}
+
static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -5510,14 +5534,11 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
int auto_jack;
if (nid == VNID_HP_SEL) {
- auto_jack =
- spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
- if (!auto_jack) {
- if (ca0132_use_alt_functions(spec))
- ca0132_alt_select_out(codec);
- else
- ca0132_select_out(codec);
- }
+ ca0132_disable_hp_auto_detect(codec);
+ if (ca0132_use_alt_functions(spec))
+ ca0132_alt_select_out(codec);
+ else
+ ca0132_select_out(codec);
return 1;
}
@@ -5978,7 +5999,6 @@ static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol,
struct ca0132_spec *spec = codec->spec;
int sel = ucontrol->value.enumerated.item[0];
unsigned int items = NUM_OF_OUTPUTS;
- unsigned int auto_jack;
if (sel >= items)
return 0;
@@ -5988,10 +6008,8 @@ static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol,
spec->out_enum_val = sel;
- auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
-
- if (!auto_jack)
- ca0132_alt_select_out(codec);
+ ca0132_disable_hp_auto_detect(codec);
+ ca0132_alt_select_out(codec);
return 1;
}
diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
index 3a9717df39b4..e3b6aaabe3a9 100644
--- a/sound/hda/codecs/conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -1175,6 +1175,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)
static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
struct conexant_spec *spec;
+ struct hda_jack_callback *callback;
int err;
codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
@@ -1190,7 +1191,12 @@ static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)
case 0x14f11f86:
case 0x14f11f87:
spec->is_cx11880_sn6140 = true;
- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref);
+ callback = snd_hda_jack_detect_enable_callback(codec, 0x19,
+ cx_update_headset_mic_vref);
+ if (IS_ERR(callback)) {
+ err = PTR_ERR(callback);
+ goto error;
+ }
break;
}
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index d720565db4aa..f180d6a72021 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -1669,6 +1669,21 @@ static void alc295_fixup_hp_mute_led_coefbit11(struct hda_codec *codec,
}
}
+/* Override wrong pin to NID 0x1b (F.32 BIOS reports 0x18 via DMI OEM string)
+ * on HP pavilion 15-cs1xxx laptops
+ */
+static void alc295_fixup_hp_pavilion_mute_led_1b(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ alc269_fixup_hp_mute_led(codec, fix, action);
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->mute_led_nid = 0x1b;
+}
+
static void alc233_fixup_lenovo_coef_micmute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3390,6 +3405,19 @@ static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
}
}
+static void alc256_fixup_xiaomi_pro15_resume(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ /*
+ * On the Xiaomi Mi Laptop Pro 15 (TM1905, SSID 1d72:1905) the ALC256
+ * codec sets coefficient 0x10 bit 9 to 1 after S3 resume, silencing
+ * the internal speaker. Bluetooth and HDMI audio are unaffected.
+ * Clear the bit so the speaker keeps working across suspend cycles.
+ */
+ alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+}
+
static void alc256_decrease_headphone_amp_val(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3694,6 +3722,17 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
spec->power_hook = alc287_s4_power_gpio3_default;
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
}
+
+static void alc287_fixup_tb_vmaster_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->gen.vmaster_mute_led = 1;
+
+ alc287_fixup_bind_dacs(codec, fix, action);
+}
/* GPIO2: mute led GPIO3: micmute led */
static void alc245_tas2781_spi_hp_fixup_muteled(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -3846,6 +3885,7 @@ enum {
ALC290_FIXUP_SUBWOOFER,
ALC290_FIXUP_SUBWOOFER_HSJACK,
ALC295_FIXUP_HP_MUTE_LED_COEFBIT11,
+ ALC295_FIXUP_HP_PAVILION_MUTE_LED_1B,
ALC269_FIXUP_THINKPAD_ACPI,
ALC269_FIXUP_LENOVO_XPAD_ACPI,
ALC269_FIXUP_DMIC_THINKPAD_ACPI,
@@ -4041,6 +4081,7 @@ enum {
ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
ALC233_FIXUP_NO_AUDIO_JACK,
ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME,
+ ALC256_FIXUP_XIAOMI_PRO15_RESUME,
ALC285_FIXUP_LEGION_Y9000X_SPEAKERS,
ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE,
ALC287_FIXUP_LEGION_16ACHG6,
@@ -4054,6 +4095,7 @@ enum {
ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED,
ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED,
ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE,
+ ALC295_FIXUP_FRAMEWORK_LAPTOP_LIMIT_INT_MIC_BOOST,
ALC287_FIXUP_LEGION_16ITHG6,
ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
@@ -4112,6 +4154,7 @@ enum {
ALC245_FIXUP_CS35L41_I2C_2_MUTE_LED,
ALC236_FIXUP_HP_DMIC,
ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO,
+ ALC245_FIXUP_HP_ENVY_X360_15_FH0XXX,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -5689,6 +5732,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc295_fixup_hp_mute_led_coefbit11,
},
+ [ALC295_FIXUP_HP_PAVILION_MUTE_LED_1B] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc295_fixup_hp_pavilion_mute_led_1b,
+ },
[ALC298_FIXUP_SAMSUNG_AMP] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc298_fixup_samsung_amp,
@@ -6229,6 +6276,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
},
+ [ALC256_FIXUP_XIAOMI_PRO15_RESUME] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc256_fixup_xiaomi_pro15_resume,
+ },
[ALC287_FIXUP_LEGION_16ACHG6] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc287_fixup_legion_16achg6_speakers,
@@ -6296,6 +6347,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
},
+ [ALC295_FIXUP_FRAMEWORK_LAPTOP_LIMIT_INT_MIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE,
+ },
[ALC287_FIXUP_LEGION_16ITHG6] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc287_fixup_legion_16ithg6_speakers,
@@ -6448,7 +6505,7 @@ static const struct hda_fixup alc269_fixups[] = {
},
[ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = {
.type = HDA_FIXUP_FUNC,
- .v.func = alc287_fixup_bind_dacs,
+ .v.func = alc287_fixup_tb_vmaster_led,
.chained = true,
.chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
},
@@ -6664,6 +6721,12 @@ static const struct hda_fixup alc269_fixups[] = {
{ 0x1b, 0x90170110 },
{ }
}
+ },
+ [ALC245_FIXUP_HP_ENVY_X360_15_FH0XXX] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_i2c_two,
+ .chained = true,
+ .chain_id = ALC245_FIXUP_HP_X360_MUTE_LEDS
}
};
@@ -6717,6 +6780,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED),
@@ -6891,9 +6955,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN),
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, 0x8536, "HP ProBook 430 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8548, "HP EliteBook x360 830 G6", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x854a, "HP EliteBook 830 G6", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x856a, "HP Pavilion 15-cs1xxx", ALC295_FIXUP_HP_PAVILION_MUTE_LED_1B),
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, 0x8603, "HP Omen 17-cb0xxx", ALC285_FIXUP_HP_MUTE_LED),
@@ -7019,6 +7085,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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, 0x8a34, "HP Pavilion x360 2-in-1 Laptop 14-ek0xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8a36, "HP Pavilion Plus 14-eh0xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8a3d, "HP Victus 15-fb0xxx (MB 8A3D)", ALC245_FIXUP_HP_MUTE_LED_V2_COEFBIT),
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),
@@ -7038,6 +7105,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8ad8, "HP 800 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x8b34, "HP 250 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8b3a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8b3f, "HP mt440 Mobile Thin Client U91", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
@@ -7085,7 +7153,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8be6, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8be7, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy x360 2-in-1 Laptop 15-fh0xxx", ALC245_FIXUP_HP_ENVY_X360_15_FH0XXX),
SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX),
@@ -7135,6 +7203,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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, 0x8cbc, "HP Pavilion Laptop 16-ag0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x8cbd, "HP Pavilion Aero Laptop 13-bg0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
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),
@@ -7163,7 +7232,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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, 0x8da8, "HP 16 Piston OmniBook X", ALC245_FIXUP_HP_ENVY_X360_15_FH0XXX),
SND_PCI_QUIRK(0x103c, 0x8dc9, "HP Laptop 15-fc0xxx", ALC236_FIXUP_HP_DMIC),
SND_PCI_QUIRK(0x103c, 0x8dd4, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS),
SND_PCI_QUIRK(0x103c, 0x8dd7, "HP Laptop 15-fd0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
@@ -7175,6 +7244,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8def, "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, 0x8df1, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8df7, "HP Z66 G6", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8dfb, "HP EliteBook 6 G1a 14", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8dfd, "HP EliteBook 6 G1a 16", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
@@ -7387,12 +7457,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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),
- SND_PCI_QUIRK(0x1043, 0x3f00, "ASUS Strix G815LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
- 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, 0x3ee0, "ASUS Strix G815_JHR_JMR_JPR", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x3ef0, "ASUS Strix G635LR_LW_LX", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x3f00, "ASUS Strix G815LH_LM_LP", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x3f10, "ASUS Strix G835LR_LW_LX", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x3f30, "ASUS Strix G815LR_LW", ALC287_FIXUP_TXNW2781_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),
@@ -7446,6 +7516,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x144d, 0xc870, "Samsung Galaxy Book2 Pro (NP950XED)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
SND_PCI_QUIRK(0x144d, 0xc872, "Samsung Galaxy Book2 Pro (NP950XEE)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
SND_PCI_QUIRK(0x144d, 0xc886, "Samsung Galaxy Book3 Pro (NP964XFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+ SND_PCI_QUIRK(0x144d, 0xc902, "Samsung Galaxy Book5 360 (NP750QHA)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xc1ca, "Samsung Galaxy Book3 Pro 360 (NP960QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x144d, 0xc1cb, "Samsung Galaxy Book3 Pro 360 (NP965QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x144d, 0xc1cc, "Samsung Galaxy Book3 Ultra (NT960XFH)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
@@ -7617,6 +7688,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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),
+ /* Yoga Pro 9 16IMH9 and Legion 7 16ITHG6 share PCI SSID 17aa:3811
+ * with Legion S7 15IMH05; use codec SSID to distinguish them
+ */
+ HDA_CODEC_QUIRK(0x17aa, 0x38d5, "Lenovo Yoga Pro 9 16IMH9", ALC287_FIXUP_TAS2781_I2C),
+ HDA_CODEC_QUIRK(0x17aa, 0x38d6, "Lenovo Yoga Pro 9 16IMH9", ALC287_FIXUP_TAS2781_I2C),
+ HDA_CODEC_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
SND_PCI_QUIRK(0x17aa, 0x3811, "Legion S7 15IMH05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7),
@@ -7690,6 +7767,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38fc, "Lenovo Yoga Pro 7 15ASH11", ALC245_FIXUP_BASS_HP_DAC),
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),
@@ -7762,9 +7840,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1d72, 0x1905, "Xiaomi Mi Laptop Pro 15", ALC256_FIXUP_XIAOMI_PRO15_RESUME),
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(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK),
+ SND_PCI_QUIRK(0x1e50, 0x7007, "Positivo DN50E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1ee7, 0x2081, "HONOR MRB-XXX M1020", ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO),
SND_PCI_QUIRK(0x1f4c, 0xe001, "Minisforum V3 (SE)", ALC245_FIXUP_BASS_HP_DAC),
@@ -7790,7 +7870,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0xf111, 0x0009, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0xf111, 0x000b, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0xf111, 0x000c, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0xf111, 0x000f, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0xf111, 0x000f, "Framework Laptop 13 Pro PTL", ALC295_FIXUP_FRAMEWORK_LAPTOP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0xf111, 0x010f, "Framework Laptop 13 PTL", ALC295_FIXUP_FRAMEWORK_LAPTOP_LIMIT_INT_MIC_BOOST),
#if 0
/* Below is a quirk table taken from the old code.
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
index fc5651e555e3..e51964c0a091 100644
--- a/sound/hda/codecs/side-codecs/Kconfig
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -94,7 +94,6 @@ menu "CS35L56 driver options"
config SND_HDA_SCODEC_CS35L56_CAL_DEBUGFS
bool "CS35L56 create debugfs for factory calibration"
- default N
depends on DEBUG_FS
select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
help
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
index b64890006bb7..acfccc848f82 100644
--- a/sound/hda/codecs/side-codecs/cs35l41_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c
@@ -1896,8 +1896,10 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
cs35l41->dacpi = adev;
physdev = get_device(acpi_get_first_physical_node(adev));
- if (!physdev)
+ if (!physdev) {
+ acpi_dev_put(adev);
return -ENODEV;
+ }
sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
if (IS_ERR(sub))
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c
index 1ace4beef508..cdbc576569ef 100644
--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c
@@ -180,11 +180,15 @@ static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
{
struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
unsigned int reg_val;
- int i;
+ int i, ret;
cs35l56_hda_wait_dsp_ready(cs35l56);
- regmap_read(cs35l56->base.regmap, kcontrol->private_value, &reg_val);
+ ret = regmap_read(cs35l56->base.regmap, kcontrol->private_value,
+ &reg_val);
+ if (ret)
+ return ret;
+
reg_val &= CS35L56_ASP_TXn_SRC_MASK;
for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {
@@ -203,15 +207,20 @@ static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
unsigned int item = ucontrol->value.enumerated.item[0];
bool changed;
+ int ret;
if (item >= CS35L56_NUM_INPUT_SRC)
return -EINVAL;
cs35l56_hda_wait_dsp_ready(cs35l56);
- regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
- CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
- &changed);
+ ret = regmap_update_bits_check(cs35l56->base.regmap,
+ kcontrol->private_value,
+ CS35L56_INPUT_MASK,
+ cs35l56_tx_input_values[item],
+ &changed);
+ if (ret)
+ return ret;
return changed;
}
@@ -967,6 +976,7 @@ static int cs35l56_hda_system_resume(struct device *dev)
static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr)
{
/* The cirrus,dev-index property has the wrong values */
+ cs35l56->num_amps = 2;
switch (*bus_addr) {
case 0x30:
cs35l56->index = 1;
@@ -1016,7 +1026,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
char hid_string[8];
struct acpi_device *adev;
const char *property, *sub;
- size_t nval;
int i, ret;
/*
@@ -1032,6 +1041,7 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
return -ENODEV;
}
ACPI_COMPANION_SET(cs35l56->base.dev, adev);
+ acpi_dev_put(adev);
}
/* Initialize things that could be overwritten by a fixup */
@@ -1052,13 +1062,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
ret = -EINVAL;
goto err;
}
- nval = ret;
+ cs35l56->num_amps = ret;
- ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
+ ret = device_property_read_u32_array(cs35l56->base.dev, property, values,
+ cs35l56->num_amps);
if (ret)
goto err;
- for (i = 0; i < nval; i++) {
+ for (i = 0; i < cs35l56->num_amps; i++) {
if (values[i] == id) {
cs35l56->index = i;
break;
@@ -1081,7 +1092,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
"Read ACPI _SUB failed(%ld): fallback to generic firmware\n",
PTR_ERR(sub));
} else {
- ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);
+ ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index,
+ cs35l56->num_amps, -1);
if (ret == -ENOENT) {
cs35l56->system_name = sub;
} else if (ret >= 0) {
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h
index cb4b5e7356a3..3705af7c186b 100644
--- a/sound/hda/codecs/side-codecs/cs35l56_hda.h
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.h
@@ -26,6 +26,7 @@ struct cs35l56_hda {
struct work_struct dsp_work;
int index;
+ int num_amps;
const char *system_name;
const char *amp_name;
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
index 560f2385212d..0e4f3553f273 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -132,10 +132,18 @@ static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,
int ret, val;
/*
- * In our TAS2781 SPI mode, read/write was masked in last bit of
- * address, it cause regmap_update_bits() not work as expected.
+ * In TAS2781 SPI mode, when accessing non-book-zero or page numbers
+ * greater than 1 in book 0, an additional byte must be read. The
+ * first byte in such cases is a dummy byte and should be ignored.
*/
- ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
+ if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
+ unsigned char buf[2];
+
+ ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, buf, 2);
+ val = buf[1];
+ } else {
+ ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
+ }
if (ret < 0) {
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
return ret;
diff --git a/sound/hda/common/auto_parser.c b/sound/hda/common/auto_parser.c
index 8923813ce424..5bc95d3116ff 100644
--- a/sound/hda/common/auto_parser.c
+++ b/sound/hda/common/auto_parser.c
@@ -1013,7 +1013,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
const char *name = NULL;
const char *type = NULL;
unsigned int vendor, device;
- u16 pci_vendor, pci_device;
+ u16 pci_vendor = 0, pci_device = 0;
u16 codec_vendor, codec_device;
if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
@@ -1066,7 +1066,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
/* match primarily with the PCI SSID */
for (q = quirk; q->subvendor || q->subdevice; q++) {
/* if the entry is specific to codec SSID, check with it */
- if (!codec->bus->pci || q->match_codec_ssid) {
+ if (!pci_vendor || !pci_device || q->match_codec_ssid) {
if (hda_quirk_match(codec_vendor, codec_device, q)) {
type = "codec SSID";
goto found_device;
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index c2af2511a831..81f266b9b850 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -1699,6 +1699,9 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
unsigned short flags = 0;
struct hda_nid_item *item;
+ if (!kctl)
+ return -EINVAL;
+
if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) {
flags |= HDA_NID_ITEM_AMP;
if (nid == 0)
diff --git a/sound/hda/common/controller.c b/sound/hda/common/controller.c
index 5934e5cdfdfd..a847546753db 100644
--- a/sound/hda/common/controller.c
+++ b/sound/hda/common/controller.c
@@ -97,6 +97,8 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
trace_azx_pcm_close(chip, azx_dev);
scoped_guard(mutex, &chip->open_mutex) {
+ if (chip->ops->pcm_close)
+ chip->ops->pcm_close(chip, azx_dev);
azx_release_device(azx_dev);
if (hinfo->ops.close)
hinfo->ops.close(hinfo, apcm->codec, substream);
@@ -1264,19 +1266,17 @@ int azx_codec_configure(struct azx *chip)
}
EXPORT_SYMBOL_GPL(azx_codec_configure);
-static int stream_direction(struct azx *chip, unsigned char index)
+void azx_add_stream(struct azx *chip, struct azx_dev *azx_dev, int idx, int tag)
{
- if (index >= chip->capture_index_offset &&
- index < chip->capture_index_offset + chip->capture_streams)
- return SNDRV_PCM_STREAM_CAPTURE;
- return SNDRV_PCM_STREAM_PLAYBACK;
+ snd_hdac_stream_init(azx_bus(chip), azx_stream(azx_dev), idx,
+ azx_stream_direction(chip, idx), tag);
}
+EXPORT_SYMBOL_GPL(azx_add_stream);
/* initialize SD streams */
int azx_init_streams(struct azx *chip)
{
int i;
- int stream_tags[2] = { 0, 0 };
/* initialize each stream (aka device)
* assign the starting bdl address to each stream (device)
@@ -1284,24 +1284,10 @@ int azx_init_streams(struct azx *chip)
*/
for (i = 0; i < chip->num_streams; i++) {
struct azx_dev *azx_dev = kzalloc_obj(*azx_dev);
- int dir, tag;
if (!azx_dev)
return -ENOMEM;
-
- dir = stream_direction(chip, i);
- /* stream tag must be unique throughout
- * the stream direction group,
- * valid values 1...15
- * use separate stream tag if the flag
- * AZX_DCAPS_SEPARATE_STREAM_TAG is used
- */
- if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG)
- tag = ++stream_tags[dir];
- else
- tag = i + 1;
- snd_hdac_stream_init(azx_bus(chip), azx_stream(azx_dev),
- i, dir, tag);
+ azx_add_stream(chip, azx_dev, i, i + 1);
}
return 0;
diff --git a/sound/hda/common/hda_controller.h b/sound/hda/common/hda_controller.h
index 7434f38038a0..38227f82e704 100644
--- a/sound/hda/common/hda_controller.h
+++ b/sound/hda/common/hda_controller.h
@@ -57,13 +57,12 @@ enum {
struct azx_dev {
struct hdac_stream core;
- unsigned int irq_pending:1;
/*
* For VIA:
* A flag to ensure DMA position is 0
* when link position is not greater than FIFO size
*/
- unsigned int insufficient:1;
+ bool insufficient;
};
#define azx_stream(dev) (&(dev)->core)
@@ -79,6 +78,8 @@ struct hda_controller_ops {
int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
/* enable/disable the link power */
int (*link_power)(struct azx *chip, bool enable);
+ /* additional hook for PCM */
+ void (*pcm_close)(struct azx *chip, struct azx_dev *azx_dev);
};
struct azx_pcm {
@@ -206,6 +207,15 @@ int azx_bus_init(struct azx *chip, const char *model);
int azx_probe_codecs(struct azx *chip, unsigned int max_slots);
int azx_codec_configure(struct azx *chip);
int azx_init_streams(struct azx *chip);
+void azx_add_stream(struct azx *chip, struct azx_dev *s, int idx, int tag);
void azx_free_streams(struct azx *chip);
+static inline int azx_stream_direction(struct azx *chip, unsigned char index)
+{
+ if (index >= chip->capture_index_offset &&
+ index < chip->capture_index_offset + chip->capture_streams)
+ return SNDRV_PCM_STREAM_CAPTURE;
+ return SNDRV_PCM_STREAM_PLAYBACK;
+}
+
#endif /* __SOUND_HDA_CONTROLLER_H */
diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
index c87d75dbd8aa..4b03c64e72ab 100644
--- a/sound/hda/controllers/intel.c
+++ b/sound/hda/controllers/intel.c
@@ -615,17 +615,17 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
/* called from IRQ */
static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
{
- struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct hda_intel_stream *istream = azx_dev_to_istream(azx_dev);
int ok;
ok = azx_position_ok(chip, azx_dev);
if (ok == 1) {
- azx_dev->irq_pending = 0;
+ istream->irq_pending = false;
return ok;
} else if (ok == 0) {
/* bogus IRQ, process it later */
- azx_dev->irq_pending = 1;
- schedule_work(&hda->irq_pending_work);
+ istream->irq_pending = true;
+ schedule_work(&istream->irq_pending_work);
}
return 0;
}
@@ -721,11 +721,13 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
*/
static void azx_irq_pending_work(struct work_struct *work)
{
- struct hda_intel *hda = container_of(work, struct hda_intel, irq_pending_work);
+ struct hda_intel_stream *istream =
+ container_of(work, struct hda_intel_stream, irq_pending_work);
+ struct azx_dev *azx_dev = &istream->azx_dev;
+ struct hda_intel *hda = istream->hda;
struct azx *chip = &hda->chip;
struct hdac_bus *bus = azx_bus(chip);
- struct hdac_stream *s;
- int pending, ok;
+ int ok;
if (!hda->irq_pending_warned) {
dev_info(chip->card->dev,
@@ -735,42 +737,51 @@ static void azx_irq_pending_work(struct work_struct *work)
}
for (;;) {
- pending = 0;
- spin_lock_irq(&bus->reg_lock);
- list_for_each_entry(s, &bus->stream_list, list) {
- struct azx_dev *azx_dev = stream_to_azx_dev(s);
- if (!azx_dev->irq_pending ||
- !s->substream ||
- !s->running)
- continue;
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ if (!istream->irq_pending ||
+ !azx_dev->core.substream ||
+ !azx_dev->core.running) {
+ return;
+ }
+
ok = azx_position_ok(chip, azx_dev);
- if (ok > 0) {
- azx_dev->irq_pending = 0;
- spin_unlock(&bus->reg_lock);
- snd_pcm_period_elapsed(s->substream);
- spin_lock(&bus->reg_lock);
- } else if (ok < 0) {
- pending = 0; /* too early */
- } else
- pending++;
+ if (ok < 0)
+ return; /* too early */
+ if (ok > 0)
+ istream->irq_pending = false;
}
- spin_unlock_irq(&bus->reg_lock);
- if (!pending)
+
+ if (ok) {
+ snd_pcm_period_elapsed(azx_dev->core.substream);
return;
+ }
+
msleep(1);
}
}
/* clear irq_pending flags and assure no on-going workq */
+static void hda_intel_stream_clear_irq_pending(struct azx_dev *azx_dev)
+{
+ struct hda_intel_stream *istream = azx_dev_to_istream(azx_dev);
+
+ istream->irq_pending = false;
+ cancel_work_sync(&istream->irq_pending_work);
+}
+
+/* called at PCM close */
+static void hda_intel_pcm_close(struct azx *chip, struct azx_dev *azx_dev)
+{
+ hda_intel_stream_clear_irq_pending(azx_dev);
+}
+
static void azx_clear_irq_pending(struct azx *chip)
{
struct hdac_bus *bus = azx_bus(chip);
struct hdac_stream *s;
- guard(spinlock_irq)(&bus->reg_lock);
list_for_each_entry(s, &bus->stream_list, list) {
- struct azx_dev *azx_dev = stream_to_azx_dev(s);
- azx_dev->irq_pending = 0;
+ hda_intel_stream_clear_irq_pending(stream_to_azx_dev(s));
}
}
@@ -1797,7 +1808,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000)
chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]);
INIT_LIST_HEAD(&chip->pcm_list);
- INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
INIT_LIST_HEAD(&hda->list);
init_vga_switcheroo(chip);
init_completion(&hda->probe_wait);
@@ -1846,6 +1856,39 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
return 0;
}
+/* create and assign streams */
+static int hda_init_streams(struct azx *chip)
+{
+ int i;
+ int stream_tags[2] = { 0, 0 };
+
+ for (i = 0; i < chip->num_streams; i++) {
+ struct hda_intel_stream *s = kzalloc_obj(*s);
+ int tag, dir;
+
+ if (!s)
+ return -ENOMEM;
+
+ s->hda = container_of(chip, struct hda_intel, chip);
+ INIT_WORK(&s->irq_pending_work, azx_irq_pending_work);
+
+ /* stream tag must be unique throughout
+ * the stream direction group,
+ * valid values 1...15
+ * use separate stream tag if the flag
+ * AZX_DCAPS_SEPARATE_STREAM_TAG is used
+ */
+ dir = azx_stream_direction(chip, i);
+ if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG)
+ tag = ++stream_tags[dir];
+ else
+ tag = i + 1;
+ azx_add_stream(chip, &s->azx_dev, i, tag);
+ }
+
+ return 0;
+}
+
static int azx_first_init(struct azx *chip)
{
int dev = chip->dev_index;
@@ -2000,7 +2043,7 @@ static int azx_first_init(struct azx *chip)
}
/* initialize streams */
- err = azx_init_streams(chip);
+ err = hda_init_streams(chip);
if (err < 0)
return err;
@@ -2099,6 +2142,7 @@ static const struct dmi_system_id driver_denylist_dmi[] = {
static const struct hda_controller_ops pci_hda_ops = {
.disable_msi_reset_irq = disable_msi_reset_irq,
.position_check = azx_position_check,
+ .pcm_close = hda_intel_pcm_close,
};
static DECLARE_BITMAP(probed_devs, SNDRV_CARDS);
diff --git a/sound/hda/controllers/intel.h b/sound/hda/controllers/intel.h
index 2d1725f86ef1..4efb3b0fc2d8 100644
--- a/sound/hda/controllers/intel.h
+++ b/sound/hda/controllers/intel.h
@@ -9,9 +9,6 @@
struct hda_intel {
struct azx chip;
- /* for pending irqs */
- struct work_struct irq_pending_work;
-
/* sync probing */
struct completion probe_wait;
struct delayed_work probe_work;
@@ -35,4 +32,16 @@ struct hda_intel {
int probe_retry; /* being probe-retry */
};
+struct hda_intel_stream {
+ struct azx_dev azx_dev;
+
+ /* for pending irqs */
+ struct hda_intel *hda;
+ struct work_struct irq_pending_work;
+ bool irq_pending;
+};
+
+#define azx_dev_to_istream(azx_dev) \
+ container_of(azx_dev, struct hda_intel_stream, azx_dev)
+
#endif
diff --git a/sound/hda/core/hdmi_chmap.c b/sound/hda/core/hdmi_chmap.c
index 7b276047f85a..c897fc443467 100644
--- a/sound/hda/core/hdmi_chmap.c
+++ b/sound/hda/core/hdmi_chmap.c
@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap,
if (hdmi_channel_mapping[ca][1] == 0) {
int hdmi_slot = 0;
/* fill actual channel mappings in ALSA channel (i) order */
- for (i = 0; i < ch_alloc->channels; i++) {
- while (!WARN_ON(hdmi_slot >= 8) &&
- !ch_alloc->speakers[7 - hdmi_slot])
- hdmi_slot++; /* skip zero slots */
+ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) {
+ while (!ch_alloc->speakers[7 - hdmi_slot]) {
+ /* skip zero slots */
+ if (++hdmi_slot >= 8)
+ goto out;
+ }
hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++;
}
+ out:
/* fill the rest of the slots with ALSA channel 0xf */
for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++)
if (!ch_alloc->speakers[7 - hdmi_slot])
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c
index d846777e7462..19f0da2e6501 100644
--- a/sound/pci/asihpi/hpicmn.c
+++ b/sound/pci/asihpi/hpicmn.c
@@ -276,6 +276,12 @@ static short find_control(u16 control_index,
return 0;
}
+ if (control_index >= p_cache->control_count) {
+ HPI_DEBUG_LOG(VERBOSE, "control_index out of bounce %d\n",
+ control_index);
+ return 0;
+ }
+
*pI = p_cache->p_info[control_index];
if (!*pI) {
HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c
index 1604ed679224..309dc9ed6e0d 100644
--- a/sound/soc/amd/acp-config.c
+++ b/sound/soc/amd/acp-config.c
@@ -30,6 +30,13 @@ static const struct dmi_system_id acp70_acpi_flag_override_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "HN7306EA"),
},
},
+ {
+ /* ASUS Zenbook S16 UM5606GA (Strix Point, ACP 7.0) */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Zenbook S16 UM5606GA"),
+ },
+ },
{}
};
diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c
index a7a551366a40..235d6cc83fa9 100644
--- a/sound/soc/amd/acp/acp-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-legacy-mach.c
@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev)
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
dmi_id = dmi_first_match(acp_quirk_table);
- if (dmi_id && dmi_id->driver_data)
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
ret = acp_legacy_dai_links_create(card);
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 09f6c9a2c041..ef784cca13f2 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -20,6 +20,7 @@
#include <sound/soc.h>
#include <linux/input.h>
#include <linux/module.h>
+#include <linux/dmi.h>
#include "../../codecs/rt5682.h"
#include "../../codecs/rt1019.h"
@@ -37,15 +38,21 @@
#define NAU8821_FREQ_OUT 12288000
#define MAX98388_CODEC_DAI "max98388-aif1"
-#define TDM_MODE_ENABLE 1
-
const struct dmi_system_id acp_quirk_table[] = {
{
/* Google skyrim proto-0 */
.matches = {
DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"),
},
- .driver_data = (void *)TDM_MODE_ENABLE,
+ .driver_data = (void *)QUIRK_TDM_MODE_ENABLE,
+ },
+ {
+ /* Valve Steam Deck OLED */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ },
+ .driver_data = (void *)QUIRK_REMAP_DMIC_BT,
},
{}
};
@@ -1401,6 +1408,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
struct snd_soc_dai_link *links;
struct device *dev = card->dev;
struct acp_card_drvdata *drv_data = card->drvdata;
+ const struct dmi_system_id *dmi_id = dmi_first_match(acp_quirk_table);
int i = 0, num_links = 0;
if (drv_data->hs_cpu_id)
@@ -1572,6 +1580,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
+
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT)
+ links[i].id = DMIC_BE_ID;
i++;
}
@@ -1587,6 +1598,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].capture_only = 1;
links[i].nonatomic = true;
links[i].no_pcm = 1;
+
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) {
+ links[i].id = BT_BE_ID;
+ dev_dbg(dev, "quirk REMAP_DMIC_BT enabled\n");
+ }
}
card->dai_link = links;
diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h
index f94c30c20f20..7177d3fd9619 100644
--- a/sound/soc/amd/acp/acp-mach.h
+++ b/sound/soc/amd/acp/acp-mach.h
@@ -26,6 +26,10 @@
#define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata)
+/* List of DMI quirks - check acp-mach-common.c for usage. */
+#define QUIRK_TDM_MODE_ENABLE 1
+#define QUIRK_REMAP_DMIC_BT 2
+
enum be_id {
HEADSET_BE_ID = 0,
AMP_BE_ID,
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index 0f21e5f64531..09b475c83c49 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -260,9 +260,9 @@ static int create_sdw_dailink(struct snd_soc_card *card,
cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
"SDW%d Pin%d",
link_num, cpu_pin_id);
- dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name);
if (!cpus->dai_name)
return -ENOMEM;
+ dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name);
codec_maps[j].cpu = 0;
codec_maps[j].codec = j;
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index 6215e31ecedd..36ecef7013b9 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev)
acp_card_drvdata = card->drvdata;
dmi_id = dmi_first_match(acp_quirk_table);
- if (dmi_id && dmi_id->driver_data)
+ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index c5cf45881416..7a637d6b5576 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -62,6 +62,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, "OMEN Gaming Laptop 16-ap0xxx"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5525"),
}
@@ -483,6 +490,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 15 C7VE"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7VF"),
}
},
@@ -671,6 +685,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_BOARD_NAME, "8E35"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "MECHREVO"),
DMI_MATCH(DMI_BOARD_NAME, "MRID6"),
}
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cf94a1c756e0..269c31ce0814 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -898,7 +898,6 @@ menu "CS35L56 driver options"
config SND_SOC_CS35L56_CAL_DEBUGFS
bool "CS35L56 create debugfs for factory calibration"
- default N
depends on DEBUG_FS
select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
help
@@ -909,7 +908,6 @@ config SND_SOC_CS35L56_CAL_DEBUGFS
config SND_SOC_CS35L56_CAL_SET_CTRL
bool "CS35L56 ALSA control to restore factory calibration"
- default N
select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
help
Allow restoring factory calibration data through an ALSA
@@ -923,7 +921,6 @@ config SND_SOC_CS35L56_CAL_SET_CTRL
config SND_SOC_CS35L56_CAL_PERFORM_CTRL
bool "CS35L56 ALSA control to perform factory calibration"
- default N
select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
help
Allow performing factory calibration data through an ALSA
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index fdda1b747bf7..6e8ef9cd1b31 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -60,19 +60,6 @@
low before proceeding with the configuration sequence */
#define AB8500_ANC_SM_DELAY 2000
-#define AB8500_FILTER_CONTROL(xname, xcount, xmin, xmax) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .info = filter_control_info, \
- .get = filter_control_get, .put = filter_control_put, \
- .private_value = (unsigned long)&(struct filter_control) \
- {.count = xcount, .min = xmin, .max = xmax} }
-
-struct filter_control {
- long min, max;
- unsigned int count;
- long value[128];
-};
-
/* Sidetone states */
static const char * const enum_sid_state[] = {
"Unconfigured",
@@ -85,45 +72,13 @@ enum sid_state {
SID_FIR_CONFIGURED = 2,
};
-static const char * const enum_anc_state[] = {
- "Unconfigured",
- "Apply FIR and IIR",
- "FIR and IIR are configured",
- "Apply FIR",
- "FIR is configured",
- "Apply IIR",
- "IIR is configured"
-};
-enum anc_state {
- ANC_UNCONFIGURED = 0,
- ANC_APPLY_FIR_IIR = 1,
- ANC_FIR_IIR_CONFIGURED = 2,
- ANC_APPLY_FIR = 3,
- ANC_FIR_CONFIGURED = 4,
- ANC_APPLY_IIR = 5,
- ANC_IIR_CONFIGURED = 6
-};
-
-/* Analog microphones */
-enum amic_idx {
- AMIC_IDX_1A,
- AMIC_IDX_1B,
- AMIC_IDX_2
-};
-
/* Private data for AB8500 device-driver */
struct ab8500_codec_drvdata {
struct regmap *regmap;
struct mutex ctrl_lock;
/* Sidetone */
- long *sid_fir_values;
enum sid_state sid_status;
-
- /* ANC */
- long *anc_fir_values;
- long *anc_iir_values;
- enum anc_state anc_status;
};
static inline const char *amic_micbias_str(enum amic_micbias micbias)
@@ -1024,89 +979,6 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = {
{"MIC2 V-AMICx Enable", NULL, "V-AMIC2"},
};
-/* ANC FIR-coefficients configuration sequence */
-static void anc_fir(struct snd_soc_component *component,
- unsigned int bnk, unsigned int par, unsigned int val)
-{
- if (par == 0 && bnk == 0)
- snd_soc_component_update_bits(component, AB8500_ANCCONF1,
- BIT(AB8500_ANCCONF1_ANCFIRUPDATE),
- BIT(AB8500_ANCCONF1_ANCFIRUPDATE));
-
- snd_soc_component_write(component, AB8500_ANCCONF5, val >> 8 & 0xff);
- snd_soc_component_write(component, AB8500_ANCCONF6, val & 0xff);
-
- if (par == AB8500_ANC_FIR_COEFFS - 1 && bnk == 1)
- snd_soc_component_update_bits(component, AB8500_ANCCONF1,
- BIT(AB8500_ANCCONF1_ANCFIRUPDATE), 0);
-}
-
-/* ANC IIR-coefficients configuration sequence */
-static void anc_iir(struct snd_soc_component *component, unsigned int bnk,
- unsigned int par, unsigned int val)
-{
- if (par == 0) {
- if (bnk == 0) {
- snd_soc_component_update_bits(component, AB8500_ANCCONF1,
- BIT(AB8500_ANCCONF1_ANCIIRINIT),
- BIT(AB8500_ANCCONF1_ANCIIRINIT));
- usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY*2);
- snd_soc_component_update_bits(component, AB8500_ANCCONF1,
- BIT(AB8500_ANCCONF1_ANCIIRINIT), 0);
- usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY*2);
- } else {
- snd_soc_component_update_bits(component, AB8500_ANCCONF1,
- BIT(AB8500_ANCCONF1_ANCIIRUPDATE),
- BIT(AB8500_ANCCONF1_ANCIIRUPDATE));
- }
- } else if (par > 3) {
- snd_soc_component_write(component, AB8500_ANCCONF7, 0);
- snd_soc_component_write(component, AB8500_ANCCONF8, val >> 16 & 0xff);
- }
-
- snd_soc_component_write(component, AB8500_ANCCONF7, val >> 8 & 0xff);
- snd_soc_component_write(component, AB8500_ANCCONF8, val & 0xff);
-
- if (par == AB8500_ANC_IIR_COEFFS - 1 && bnk == 1)
- snd_soc_component_update_bits(component, AB8500_ANCCONF1,
- BIT(AB8500_ANCCONF1_ANCIIRUPDATE), 0);
-}
-
-/* ANC IIR-/FIR-coefficients configuration sequence */
-static void anc_configure(struct snd_soc_component *component,
- bool apply_fir, bool apply_iir)
-{
- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
- unsigned int bnk, par, val;
-
- dev_dbg(component->dev, "%s: Enter.\n", __func__);
-
- if (apply_fir)
- snd_soc_component_update_bits(component, AB8500_ANCCONF1,
- BIT(AB8500_ANCCONF1_ENANC), 0);
-
- snd_soc_component_update_bits(component, AB8500_ANCCONF1,
- BIT(AB8500_ANCCONF1_ENANC), BIT(AB8500_ANCCONF1_ENANC));
-
- if (apply_fir)
- for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
- for (par = 0; par < AB8500_ANC_FIR_COEFFS; par++) {
- val = snd_soc_component_read(component,
- drvdata->anc_fir_values[par]);
- anc_fir(component, bnk, par, val);
- }
-
- if (apply_iir)
- for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
- for (par = 0; par < AB8500_ANC_IIR_COEFFS; par++) {
- val = snd_soc_component_read(component,
- drvdata->anc_iir_values[par]);
- anc_iir(component, bnk, par, val);
- }
-
- dev_dbg(component->dev, "%s: Exit.\n", __func__);
-}
-
/*
* Control-events
*/
@@ -1130,7 +1002,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
- unsigned int param, sidconf, val;
+ unsigned int param, sidconf;
int status = 1;
dev_dbg(component->dev, "%s: Enter\n", __func__);
@@ -1159,9 +1031,8 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
snd_soc_component_write(component, AB8500_SIDFIRADR, 0);
for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) {
- val = snd_soc_component_read(component, drvdata->sid_fir_values[param]);
- snd_soc_component_write(component, AB8500_SIDFIRCOEF1, val >> 8 & 0xff);
- snd_soc_component_write(component, AB8500_SIDFIRCOEF2, val & 0xff);
+ snd_soc_component_write(component, AB8500_SIDFIRCOEF1, 0);
+ snd_soc_component_write(component, AB8500_SIDFIRCOEF2, 0);
}
snd_soc_component_update_bits(component, AB8500_SIDFIRADR,
@@ -1180,136 +1051,6 @@ out:
return status;
}
-static int anc_status_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
-
- mutex_lock(&drvdata->ctrl_lock);
- ucontrol->value.enumerated.item[0] = drvdata->anc_status;
- mutex_unlock(&drvdata->ctrl_lock);
-
- return 0;
-}
-
-static int anc_status_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
- struct device *dev = component->dev;
- bool apply_fir, apply_iir;
- unsigned int req;
- int status;
-
- dev_dbg(dev, "%s: Enter.\n", __func__);
-
- mutex_lock(&drvdata->ctrl_lock);
-
- req = ucontrol->value.enumerated.item[0];
- if (req >= ARRAY_SIZE(enum_anc_state)) {
- status = -EINVAL;
- goto cleanup;
- }
- if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&
- req != ANC_APPLY_IIR) {
- dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n",
- __func__, enum_anc_state[req]);
- status = -EINVAL;
- goto cleanup;
- }
- apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
- apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
-
- status = snd_soc_dapm_force_enable_pin(dapm, "ANC Configure Input");
- if (status < 0) {
- dev_err(dev,
- "%s: ERROR: Failed to enable power (status = %d)!\n",
- __func__, status);
- goto cleanup;
- }
- snd_soc_dapm_sync(dapm);
-
- anc_configure(component, apply_fir, apply_iir);
-
- if (apply_fir) {
- if (drvdata->anc_status == ANC_IIR_CONFIGURED)
- drvdata->anc_status = ANC_FIR_IIR_CONFIGURED;
- else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED)
- drvdata->anc_status = ANC_FIR_CONFIGURED;
- }
- if (apply_iir) {
- if (drvdata->anc_status == ANC_FIR_CONFIGURED)
- drvdata->anc_status = ANC_FIR_IIR_CONFIGURED;
- else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED)
- drvdata->anc_status = ANC_IIR_CONFIGURED;
- }
-
- status = snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
- snd_soc_dapm_sync(dapm);
-
-cleanup:
- mutex_unlock(&drvdata->ctrl_lock);
-
- if (status < 0)
- dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n",
- __func__, status);
-
- dev_dbg(dev, "%s: Exit.\n", __func__);
-
- return (status < 0) ? status : 1;
-}
-
-static int filter_control_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct filter_control *fc =
- (struct filter_control *)kcontrol->private_value;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = fc->count;
- uinfo->value.integer.min = fc->min;
- uinfo->value.integer.max = fc->max;
-
- return 0;
-}
-
-static int filter_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct ab8500_codec_drvdata *drvdata = snd_soc_component_get_drvdata(component);
- struct filter_control *fc =
- (struct filter_control *)kcontrol->private_value;
- unsigned int i;
-
- mutex_lock(&drvdata->ctrl_lock);
- for (i = 0; i < fc->count; i++)
- ucontrol->value.integer.value[i] = fc->value[i];
- mutex_unlock(&drvdata->ctrl_lock);
-
- return 0;
-}
-
-static int filter_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct ab8500_codec_drvdata *drvdata = snd_soc_component_get_drvdata(component);
- struct filter_control *fc =
- (struct filter_control *)kcontrol->private_value;
- unsigned int i;
-
- mutex_lock(&drvdata->ctrl_lock);
- for (i = 0; i < fc->count; i++)
- fc->value[i] = ucontrol->value.integer.value[i];
- mutex_unlock(&drvdata->ctrl_lock);
-
- return 0;
-}
-
/*
* Controls - Non-DAPM ASoC
*/
@@ -1597,7 +1338,6 @@ static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast,
static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state);
/* ANC */
-static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_ancstate, enum_anc_state);
static struct snd_kcontrol_new ab8500_ctrls[] = {
/* Charge pump */
@@ -1873,8 +1613,6 @@ static struct snd_kcontrol_new ab8500_ctrls[] = {
AB8500_FIFOCONF6_BFIFOSAMPLE_MAX, 0),
/* ANC */
- SOC_ENUM_EXT("ANC Status", soc_enum_ancstate,
- anc_status_control_get, anc_status_control_put),
SOC_SINGLE_XR_SX("ANC Warp Delay Shift",
AB8500_ANCCONF2, 1, AB8500_ANCCONF2_SHIFT,
AB8500_ANCCONF2_MIN, AB8500_ANCCONF2_MAX, 0),
@@ -1895,21 +1633,6 @@ static struct snd_kcontrol_new ab8500_ctrls[] = {
AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0),
};
-static struct snd_kcontrol_new ab8500_filter_controls[] = {
- AB8500_FILTER_CONTROL("ANC FIR Coefficients", AB8500_ANC_FIR_COEFFS,
- AB8500_ANC_FIR_COEFF_MIN, AB8500_ANC_FIR_COEFF_MAX),
- AB8500_FILTER_CONTROL("ANC IIR Coefficients", AB8500_ANC_IIR_COEFFS,
- AB8500_ANC_IIR_COEFF_MIN, AB8500_ANC_IIR_COEFF_MAX),
- AB8500_FILTER_CONTROL("Sidetone FIR Coefficients",
- AB8500_SID_FIR_COEFFS, AB8500_SID_FIR_COEFF_MIN,
- AB8500_SID_FIR_COEFF_MAX)
-};
-enum ab8500_filter {
- AB8500_FILTER_ANC_FIR = 0,
- AB8500_FILTER_ANC_IIR = 1,
- AB8500_FILTER_SID_FIR = 2,
-};
-
/*
* Extended interface for codec-driver
*/
@@ -2454,7 +2177,6 @@ static int ab8500_codec_probe(struct snd_soc_component *component)
struct device_node *np = dev->of_node;
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
struct ab8500_codec_platform_data codec_pdata;
- struct filter_control *fc;
int status;
dev_dbg(dev, "%s: Enter.\n", __func__);
@@ -2486,25 +2208,6 @@ static int ab8500_codec_probe(struct snd_soc_component *component)
snd_soc_component_write(component, AB8500_SHORTCIRCONF,
BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
- /* Add filter controls */
- status = snd_soc_add_component_controls(component, ab8500_filter_controls,
- ARRAY_SIZE(ab8500_filter_controls));
- if (status < 0) {
- dev_err(dev,
- "%s: failed to add ab8500 filter controls (%d).\n",
- __func__, status);
- return status;
- }
- fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value;
- drvdata->anc_fir_values = (long *)fc->value;
- fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value;
- drvdata->anc_iir_values = (long *)fc->value;
- fc = (struct filter_control *)
- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
- drvdata->sid_fir_values = (long *)fc->value;
-
snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
mutex_init(&drvdata->ctrl_lock);
@@ -2538,7 +2241,6 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
if (!drvdata)
return -ENOMEM;
drvdata->sid_status = SID_UNCONFIGURED;
- drvdata->anc_status = ANC_UNCONFIGURED;
dev_set_drvdata(&pdev->dev, drvdata);
drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev,
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c
index 3602b5b9f7d7..dd09bac652f7 100644
--- a/sound/soc/codecs/aw88395/aw88395.c
+++ b/sound/soc/codecs/aw88395/aw88395.c
@@ -456,8 +456,6 @@ static void aw88395_hw_reset(struct aw88395 *aw88395)
usleep_range(AW88395_1000_US, AW88395_1000_US + 10);
gpiod_set_value_cansleep(aw88395->reset_gpio, 1);
usleep_range(AW88395_1000_US, AW88395_1000_US + 10);
- } else {
- dev_err(aw88395->aw_pa->dev, "%s failed", __func__);
}
}
@@ -522,9 +520,10 @@ static int aw88395_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, aw88395);
aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(aw88395->reset_gpio))
- dev_info(&i2c->dev, "reset gpio not defined\n");
-
+ if (IS_ERR(aw88395->reset_gpio)) {
+ return dev_err_probe(&i2c->dev, PTR_ERR(aw88395->reset_gpio),
+ "failed to get reset gpio\n");
+ }
/* hardware reset */
aw88395_hw_reset(aw88395);
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index b34b1f5f121f..fb5b950e584c 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -118,7 +118,7 @@ static int cs_amp_read_cal_coeff(struct cs_dsp *dsp,
}
if (ret < 0) {
- dev_err(dsp->dev, "Failed to write to '%s': %d\n", ctl_name, ret);
+ dev_err(dsp->dev, "Failed to read '%s': %d\n", ctl_name, ret);
return ret;
}
@@ -500,7 +500,7 @@ static int _cs_amp_set_efi_calibration_data(struct device *dev, int amp_index, i
* must be set.
*/
if (data->count == 0)
- data->count = (data->size - sizeof(data)) / sizeof(data->data[0]);
+ data->count = (data->size - struct_offset(data, data)) / sizeof(data->data[0]);
if (amp_index < 0) {
/* Is there already a slot for this target? */
@@ -833,11 +833,18 @@ EXPORT_SYMBOL_NS_GPL(cs_amp_devm_get_vendor_specific_variant_id, "SND_SOC_CS_AMP
*/
struct dentry *cs_amp_create_debugfs(struct device *dev)
{
- struct dentry *dir;
+ struct dentry *dir, *created;
+ /* debugfs_lookup() can return NULL or ERR_PTR on error */
dir = debugfs_lookup("cirrus_logic", NULL);
- if (!dir)
- dir = debugfs_create_dir("cirrus_logic", NULL);
+ if (!IS_ERR_OR_NULL(dir)) {
+ created = debugfs_create_dir(dev_name(dev), dir);
+ dput(dir);
+
+ return created;
+ }
+
+ dir = debugfs_create_dir("cirrus_logic", NULL);
return debugfs_create_dir(dev_name(dev), dir);
}
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 9dc47fec1ea0..88e0aac540d6 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -385,18 +385,19 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,
switch (status) {
case SDW_SLAVE_ATTACHED:
- dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__);
cs35l56->sdw_in_clock_stop_1 = false;
if (cs35l56->sdw_attached)
break;
+ dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__);
if (!cs35l56->base.init_done || cs35l56->soft_resetting)
cs35l56_sdw_init(peripheral);
cs35l56->sdw_attached = true;
break;
case SDW_SLAVE_UNATTACHED:
- dev_dbg(cs35l56->base.dev, "%s: UNATTACHED\n", __func__);
+ if (cs35l56->sdw_attached)
+ dev_dbg(cs35l56->base.dev, "%s: UNATTACHED\n", __func__);
cs35l56->sdw_attached = false;
break;
default:
@@ -584,10 +585,11 @@ static void cs35l56_sdw_remove(struct sdw_slave *peripheral)
/* Disable SoundWire interrupts */
cs35l56->sdw_irq_no_unmask = true;
- cancel_work_sync(&cs35l56->sdw_irq_work);
+ flush_work(&cs35l56->sdw_irq_work);
sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0);
sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1);
sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
+ flush_work(&cs35l56->sdw_irq_work);
cs35l56_remove(cs35l56);
}
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index e05d975ba794..795e2764d67e 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -108,8 +108,6 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED");
static const struct reg_default cs35l56_reg_defaults[] = {
- /* no defaults for OTP_MEM - first read populates cache */
-
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
@@ -138,8 +136,6 @@ static const struct reg_default cs35l56_reg_defaults[] = {
};
static const struct reg_default cs35l63_reg_defaults[] = {
- /* no defaults for OTP_MEM - first read populates cache */
-
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
@@ -282,6 +278,9 @@ static bool cs35l56_common_volatile_reg(unsigned int reg)
case CS35L56_GLOBAL_ENABLES: /* owned by firmware */
case CS35L56_BLOCK_ENABLES: /* owned by firmware */
case CS35L56_BLOCK_ENABLES2: /* owned by firmware */
+ case CS35L56_OTP_MEM_53:
+ case CS35L56_OTP_MEM_54:
+ case CS35L56_OTP_MEM_55:
case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG:
case CS35L56_UPDATE_REGS:
case CS35L56_REFCLK_INPUT: /* owned by firmware */
@@ -852,9 +851,11 @@ out_sync:
err:
regcache_cache_only(cs35l56_base->regmap, true);
- regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
- cs35l56_hibernate_seq,
- ARRAY_SIZE(cs35l56_hibernate_seq));
+ if (cs35l56_base->can_hibernate) {
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l56_hibernate_seq,
+ ARRAY_SIZE(cs35l56_hibernate_seq));
+ }
return ret;
}
@@ -1729,8 +1730,7 @@ int cs35l56_read_onchip_spkid(struct cs35l56_base *cs35l56_base)
ret = regmap_read(regmap, CS35L56_GPIO_STATUS1, &val);
if (ret) {
- dev_err(cs35l56_base->dev, "GPIO%d status read failed: %d\n",
- cs35l56_base->onchip_spkid_gpios[i] + 1, ret);
+ dev_err(cs35l56_base->dev, "GPIO status read failed: %d\n", ret);
return ret;
}
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 378017fcea10..4fbbdcc87151 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -867,11 +867,16 @@ static void cs35l56_dsp_work(struct work_struct *work)
if (!cs35l56->base.init_done)
return;
- pm_runtime_get_sync(cs35l56->base.dev);
+ PM_RUNTIME_ACQUIRE(cs35l56->base.dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret) {
+ dev_err(cs35l56->base.dev, "dsp_work failed to runtime-resume: %d\n", ret);
+ return;
+ }
ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &firmware_version);
if (ret)
- goto err;
+ return;
/* Populate fw file qualifier with the revision and security state */
kfree(cs35l56->dsp.fwf_name);
@@ -887,7 +892,7 @@ static void cs35l56_dsp_work(struct work_struct *work)
}
if (!cs35l56->dsp.fwf_name)
- goto err;
+ return;
dev_dbg(cs35l56->base.dev, "DSP fwf name: '%s' system name: '%s'\n",
cs35l56->dsp.fwf_name, cs35l56->dsp.system_name);
@@ -905,8 +910,6 @@ static void cs35l56_dsp_work(struct work_struct *work)
cs35l56_patch(cs35l56, firmware_missing);
cs35l56_log_tuning(&cs35l56->base, &cs35l56->dsp.cs_dsp);
-err:
- pm_runtime_put_autosuspend(cs35l56->base.dev);
}
static struct snd_soc_dapm_context *cs35l56_power_up_for_cal(struct cs35l56_private *cs35l56)
@@ -1956,9 +1959,9 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
goto err;
}
- ret = devm_snd_soc_register_component(cs35l56->base.dev,
- &soc_component_dev_cs35l56,
- cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
+ ret = snd_soc_register_component(cs35l56->base.dev,
+ &soc_component_dev_cs35l56,
+ cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
if (ret < 0) {
dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
goto err;
@@ -1970,6 +1973,9 @@ err:
gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
+ if (cs35l56->dsp_wq)
+ destroy_workqueue(cs35l56->dsp_wq);
+
return ret;
}
EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, "SND_SOC_CS35L56_CORE");
@@ -2057,6 +2063,8 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_init, "SND_SOC_CS35L56_CORE");
void cs35l56_remove(struct cs35l56_private *cs35l56)
{
+ snd_soc_unregister_component(cs35l56->base.dev);
+
cs35l56->base.init_done = false;
/*
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
index 8d418cae371a..449d9574b03a 100644
--- a/sound/soc/codecs/es8389.c
+++ b/sound/soc/codecs/es8389.c
@@ -892,7 +892,7 @@ static int es8389_probe(struct snd_soc_component *component)
return ret;
}
- es8389->mclk = devm_clk_get(component->dev, "mclk");
+ es8389->mclk = devm_clk_get_optional(component->dev, "mclk");
if (IS_ERR(es8389->mclk))
return dev_err_probe(component->dev, PTR_ERR(es8389->mclk),
"ES8389 is unable to get mclk\n");
diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c
index e6195b71adad..eda716f817b5 100644
--- a/sound/soc/codecs/fs210x.c
+++ b/sound/soc/codecs/fs210x.c
@@ -968,7 +968,7 @@ static int fs210x_effect_scene_info(struct snd_kcontrol *kcontrol,
if (scene->name)
name = scene->name;
- strscpy(uinfo->value.enumerated.name, name, strlen(name) + 1);
+ strscpy(uinfo->value.enumerated.name, name);
return 0;
}
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index a70e8ea166dc..fdef98ce52f1 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -235,7 +235,7 @@ static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
switch (snd_soc_dapm_get_bias_level(dapm)) {
@@ -264,7 +264,7 @@ static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
switch (snd_soc_dapm_get_bias_level(dapm)) {
@@ -293,7 +293,7 @@ static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
switch (snd_soc_dapm_get_bias_level(dapm)) {
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 423b7073b302..55211266927d 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -684,18 +684,33 @@ static int tas2764_read_die_temp(struct tas2764_priv *tas2764, long *result)
* As per datasheet, subtract 93 from raw value to get degrees
* Celsius. hwmon wants millidegrees.
*
- * NOTE: The chip will initialise the TAS2764_TEMP register to
- * 2.6 *C to avoid triggering temperature protection. Since the
- * ADC is powered down during software shutdown, this value will
- * persist until the chip is fully powered up (e.g. the PCM it's
- * attached to is opened). The ADC will power down again when
- * the chip is put back into software shutdown, with the last
- * value sampled persisting in the ADC's register.
+ * NOTE: The TAS2764 datasheet mentions initialising TAS2764_TEMP
+ * such that the temperature is 2.6 *C, however the register
+ * is actually initialised to 0. The ADC is also powered down during
+ * software shutdown. The last sampled temperature will persist
+ * in the register while the amp is in this power state.
*/
+ if (reg == 0)
+ return -ENODATA;
+
*result = (reg - 93) * 1000;
return 0;
}
+static int tas2764_hwmon_is_fault(struct tas2764_priv *tas2764, long *result)
+{
+ int ret;
+ long temp;
+
+ ret = tas2764_read_die_temp(tas2764, &temp);
+ if (ret == -ENODATA) {
+ *result = true;
+ return 0;
+ }
+
+ return ret;
+}
+
static umode_t tas2764_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type, u32 attr,
int channel)
@@ -705,6 +720,7 @@ static umode_t tas2764_hwmon_is_visible(const void *data,
switch (attr) {
case hwmon_temp_input:
+ case hwmon_temp_fault:
return 0444;
default:
break;
@@ -724,6 +740,9 @@ static int tas2764_hwmon_read(struct device *dev,
case hwmon_temp_input:
ret = tas2764_read_die_temp(tas2764, val);
break;
+ case hwmon_temp_fault:
+ ret = tas2764_hwmon_is_fault(tas2764, val);
+ break;
default:
ret = -EOPNOTSUPP;
break;
@@ -733,7 +752,7 @@ static int tas2764_hwmon_read(struct device *dev,
}
static const struct hwmon_channel_info *const tas2764_hwmon_info[] = {
- HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_FAULT),
NULL
};
@@ -904,6 +923,7 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case TAS2764_SW_RST:
+ case TAS2764_TEMP:
case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:
case TAS2764_INT_CLK_CFG:
return true;
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index d4d7d056141b..dbda9f327535 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -624,7 +624,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)
/*
* As per datasheet: divide register by 16 and subtract 93 to get
* degrees Celsius. hwmon requires millidegrees. Let's avoid rounding
- * errors by subtracting 93 * 16 then multiplying by 1000 / 16.
+ * errors by subtracting 93 * 16 and scaling before dividing.
*
* NOTE: The ADC registers are initialised to 0 on reset. This means
* that the temperature will read -93 *C until the chip is brought out
@@ -633,10 +633,27 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)
* value read back from its registers will be the last value sampled
* before entering software shutdown.
*/
- *result = (reading - (93 * 16)) * (1000 / 16);
+ if (reading == 0)
+ return -ENODATA;
+
+ *result = (reading - (93 * 16)) * 1000 / 16;
return 0;
}
+static int tas2770_hwmon_is_fault(struct tas2770_priv *tas2770, long *result)
+{
+ int ret;
+ long temp;
+
+ ret = tas2770_read_die_temp(tas2770, &temp);
+ if (ret == -ENODATA) {
+ *result = true;
+ return 0;
+ }
+
+ return ret;
+}
+
static umode_t tas2770_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type, u32 attr,
int channel)
@@ -646,6 +663,7 @@ static umode_t tas2770_hwmon_is_visible(const void *data,
switch (attr) {
case hwmon_temp_input:
+ case hwmon_temp_fault:
return 0444;
default:
break;
@@ -665,6 +683,9 @@ static int tas2770_hwmon_read(struct device *dev,
case hwmon_temp_input:
ret = tas2770_read_die_temp(tas2770, val);
break;
+ case hwmon_temp_fault:
+ ret = tas2770_hwmon_is_fault(tas2770, val);
+ break;
default:
ret = -EOPNOTSUPP;
break;
@@ -674,7 +695,7 @@ static int tas2770_hwmon_read(struct device *dev,
}
static const struct hwmon_channel_info *const tas2770_hwmon_info[] = {
- HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_FAULT),
NULL
};
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index 10a2d598caa7..72a53f95d688 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -547,6 +547,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w,
WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
BIT(2), BIT(2));
snd_soc_component_update_bits(component,
+ WCD937X_AUX_AUXPA,
+ BIT(4), BIT(4));
+ snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
BIT(2), BIT(2));
snd_soc_component_update_bits(component,
@@ -562,6 +565,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
BIT(2), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_AUX_AUXPA,
+ BIT(4), 0x00);
break;
}
@@ -730,10 +736,23 @@ static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component,
WCD937X_ANA_RX_SUPPLIES,
BIT(1), BIT(1));
+ /* Enable AUX PA related RX supplies */
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(6), BIT(6));
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(7), BIT(7));
enable_irq(wcd937x->aux_pdm_wd_int);
break;
case SND_SOC_DAPM_PRE_PMD:
disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(6), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(7), 0x00);
break;
case SND_SOC_DAPM_POST_PMD:
usleep_range(2000, 2010);
@@ -2051,7 +2070,12 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
wcd937x_get_swr_port, wcd937x_set_swr_port),
SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0,
wcd937x_get_swr_port, wcd937x_set_swr_port),
-
+ SOC_SINGLE_EXT("CLSH PA Switch", WCD937X_CLSH, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DSD_L Switch", WCD937X_DSD_L, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DSD_R Switch", WCD937X_DSD_R, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0,
wcd937x_get_swr_port, wcd937x_set_swr_port),
SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0,
diff --git a/sound/soc/codecs/wm_adsp_fw_find_test.c b/sound/soc/codecs/wm_adsp_fw_find_test.c
index d0c7fb30a95d..ae686dc4fa94 100644
--- a/sound/soc/codecs/wm_adsp_fw_find_test.c
+++ b/sound/soc/codecs/wm_adsp_fw_find_test.c
@@ -45,6 +45,34 @@ struct wm_adsp_fw_find_test_params {
/* Dummy struct firmware to return from wm_adsp_request_firmware_files */
static const struct firmware wm_adsp_find_test_dummy_firmware;
+static void wm_adsp_fw_find_test_release_firmware_files_stub(struct wm_adsp_fw_files *fw)
+{
+ /*
+ * fw->wmfw.firmware and fw->coeff.firmware allocated by this KUnit
+ * test are dummies not allocated by the real request_firmware() call
+ * so they must not be passed to release_firmware().
+ * This function replaces wm_adsp_release_firmware_files().
+ */
+
+ if (!fw)
+ return;
+
+ kfree(fw->wmfw.filename);
+ kfree(fw->coeff.filename);
+
+ fw->wmfw.firmware = NULL;
+ fw->coeff.firmware = NULL;
+ fw->wmfw.filename = NULL;
+ fw->coeff.filename = NULL;
+}
+
+static void wm_adsp_free_found_fw(struct kunit *test)
+{
+ struct wm_adsp_fw_find_test *priv = test->priv;
+
+ wm_adsp_fw_find_test_release_firmware_files_stub(&priv->found_fw);
+}
+
/* Simple lookup of a filename in a list of names */
static int wm_adsp_fw_find_test_firmware_request_simple_stub(const struct firmware **firmware,
const char *filename,
@@ -97,9 +125,14 @@ static void wm_adsp_fw_find_test_pick_file(struct kunit *test)
kunit_activate_static_stub(test,
wm_adsp_firmware_request,
wm_adsp_fw_find_test_firmware_request_simple_stub);
+ kunit_activate_static_stub(test,
+ wm_adsp_release_firmware_files,
+ wm_adsp_fw_find_test_release_firmware_files_stub);
ret = wm_adsp_request_firmware_files(dsp, &priv->found_fw);
kunit_deactivate_static_stub(test, wm_adsp_firmware_request);
+ kunit_deactivate_static_stub(test, wm_adsp_release_firmware_files);
+
KUNIT_EXPECT_EQ_MSG(test, ret,
(params->expect_wmfw || params->expect_bin) ? 0 : -ENOENT,
"%s\n", priv->searched_fw_files);
@@ -173,10 +206,13 @@ static void wm_adsp_fw_find_test_search_order(struct kunit *test)
kunit_activate_static_stub(test,
wm_adsp_firmware_request,
wm_adsp_fw_find_test_firmware_request_stub);
+ kunit_activate_static_stub(test,
+ wm_adsp_release_firmware_files,
+ wm_adsp_fw_find_test_release_firmware_files_stub);
wm_adsp_request_firmware_files(dsp, &priv->found_fw);
-
kunit_deactivate_static_stub(test, wm_adsp_firmware_request);
+ kunit_deactivate_static_stub(test, wm_adsp_release_firmware_files);
KUNIT_EXPECT_STREQ(test, priv->searched_fw_files, params->expected_searches);
@@ -201,6 +237,7 @@ static void wm_adsp_fw_find_test_find_firmware_byindex(struct kunit *test)
dsp->cs_dsp.name = "cs1234";
dsp->part = "dsp1";
+
for (dsp->fw = 0;; dsp->fw++) {
fw_name = wm_adsp_get_fwf_name_by_index(dsp->fw);
if (!fw_name)
@@ -209,14 +246,22 @@ static void wm_adsp_fw_find_test_find_firmware_byindex(struct kunit *test)
kunit_activate_static_stub(test,
wm_adsp_firmware_request,
wm_adsp_fw_find_test_firmware_request_stub);
+ kunit_activate_static_stub(test,
+ wm_adsp_release_firmware_files,
+ wm_adsp_fw_find_test_release_firmware_files_stub);
wm_adsp_request_firmware_files(dsp, &priv->found_fw);
+
kunit_deactivate_static_stub(test, wm_adsp_firmware_request);
+ kunit_deactivate_static_stub(test, wm_adsp_release_firmware_files);
KUNIT_EXPECT_NOT_NULL_MSG(test,
strstr(priv->searched_fw_files, fw_name),
"fw#%d Did not find '%s' in '%s'\n",
dsp->fw, fw_name, priv->searched_fw_files);
+
+ wm_adsp_free_found_fw(test);
+ memset(priv->searched_fw_files, 0, sizeof(priv->searched_fw_files));
}
}
@@ -255,15 +300,7 @@ static int wm_adsp_fw_find_test_case_init(struct kunit *test)
static void wm_adsp_fw_find_test_case_exit(struct kunit *test)
{
- struct wm_adsp_fw_find_test *priv = test->priv;
-
- /*
- * priv->found_wmfw_firmware and priv->found_bin_firmware are
- * dummies not allocated by the real request_firmware() call they
- * must not be passed to release_firmware().
- */
- kfree(priv->found_fw.wmfw.filename);
- kfree(priv->found_fw.coeff.filename);
+ wm_adsp_free_found_fw(test);
}
static void wm_adsp_fw_find_test_param_desc(const struct wm_adsp_fw_find_test_params *param,
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index bd336d2e4cb3..e364552c1f47 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -1370,6 +1370,31 @@ static int fsl_sai_check_version(struct device *dev)
return 0;
}
+static int fsl_sai_reset_hw(struct device *dev)
+{
+ struct fsl_sai *sai = dev_get_drvdata(dev);
+ unsigned char ofs = sai->soc_data->reg_offset;
+ int ret;
+
+ /*
+ * Clear TCSR/RCSR to reset SAI and disable all interrupts.
+ * Bootloader may leave SAI running causing interrupt storm.
+ */
+ ret = regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
+ if (ret) {
+ dev_err(dev, "Failed to clear TCSR: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
+ if (ret) {
+ dev_err(dev, "Failed to clear RCSR: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* Calculate the offset between first two datalines, don't
* different offset in one case.
@@ -1575,13 +1600,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED,
- np->name, sai);
- if (ret) {
- dev_err(dev, "failed to claim irq %u\n", irq);
- return ret;
- }
-
memcpy(&sai->cpu_dai_drv, fsl_sai_dai_template,
sizeof(*fsl_sai_dai_template) * ARRAY_SIZE(fsl_sai_dai_template));
@@ -1656,6 +1674,10 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (ret < 0)
dev_warn(dev, "Error reading SAI version: %d\n", ret);
+ ret = fsl_sai_reset_hw(dev);
+ if (ret < 0)
+ dev_warn(dev, "Failed to reset hardware: %d\n", ret);
+
/* Select MCLK direction */
if (sai->mclk_direction_output &&
sai->soc_data->max_register >= FSL_SAI_MCTL) {
@@ -1667,6 +1689,13 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (ret < 0 && ret != -ENOSYS)
goto err_pm_get_sync;
+ ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED,
+ np->name, sai);
+ if (ret) {
+ dev_err(dev, "failed to claim irq %u\n", irq);
+ goto err_pm_get_sync;
+ }
+
if (of_device_is_compatible(np, "fsl,imx952-sai") &&
!of_property_read_string(np, "fsl,sai-amix-mode", &str)) {
if (!strcmp(str, "bypass"))
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index ee16cf681488..6677d3bf36ec 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -228,10 +228,14 @@ static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+ int changed;
- memcpy(xcvr->cap_ds, ucontrol->value.bytes.data, FSL_XCVR_CAPDS_SIZE);
+ changed = memcmp(xcvr->cap_ds, ucontrol->value.bytes.data,
+ sizeof(xcvr->cap_ds)) != 0;
+ memcpy(xcvr->cap_ds, ucontrol->value.bytes.data,
+ sizeof(xcvr->cap_ds));
- return 0;
+ return changed;
}
static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = {
@@ -1040,10 +1044,15 @@ static int fsl_xcvr_tx_cs_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+ int changed;
- memcpy(xcvr->tx_iec958.status, ucontrol->value.iec958.status, 24);
+ changed = memcmp(xcvr->tx_iec958.status,
+ ucontrol->value.iec958.status,
+ sizeof(xcvr->tx_iec958.status)) != 0;
+ memcpy(xcvr->tx_iec958.status, ucontrol->value.iec958.status,
+ sizeof(xcvr->tx_iec958.status));
- return 0;
+ return changed;
}
static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = {
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index 4879f79aef29..4aa0cf49b033 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -170,6 +170,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000);
if (ret) {
dev_err(card->dev, "Error setting codec sysclk: %d\n", ret);
+ clk_disable_unprepare(priv->mclk);
return ret;
}
} else {
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index c18ec607e029..ce7718338e6b 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -837,6 +837,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
SOF_BT_OFFLOAD_SSP(2) |
SOF_SSP_BT_OFFLOAD_PRESENT),
},
+ /* Novalake devices*/
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_nvlrvp"),
+ },
+ .driver_data = (void *)(SOC_SDW_PCH_DMIC),
+ },
{}
};
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 c952f7d2b2c0..52c5b5719f51 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 "soc-acpi-intel-sdca-quirks.h"
#include "sof-function-topology-lib.h"
static const struct snd_soc_acpi_endpoint single_endpoint = {
@@ -237,6 +238,15 @@ static const struct snd_soc_acpi_adr_device rt722_0_agg_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt712_0_agg_adr[] = {
+ {
+ .adr = 0x000030025D071201ull,
+ .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints),
+ .endpoints = jack_amp_g1_dmic_endpoints,
+ .name_prefix = "rt712"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = {
{
.adr = 0x000330025D131601ull,
@@ -255,6 +265,15 @@ static const struct snd_soc_acpi_adr_device rt1320_2_single_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1320_3_group1_adr[] = {
+ {
+ .adr = 0x000330025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
static const struct snd_soc_acpi_link_adr arl_cs42l43_l0[] = {
{
.mask = BIT(0),
@@ -404,6 +423,20 @@ static const struct snd_soc_acpi_link_adr arl_rt722_l0_rt1320_l2[] = {
{}
};
+static const struct snd_soc_acpi_link_adr arl_rt712_l0_rt1320_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt712_0_agg_adr),
+ .adr_d = rt712_0_agg_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1320_3_group1_adr),
+ .adr_d = rt1320_3_group1_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_codecs arl_essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
@@ -483,31 +516,39 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
- .link_mask = BIT(0),
- .links = arl_cs42l43_l0,
+ .link_mask = BIT(0) | BIT(2),
+ .links = arl_rt722_l0_rt1320_l2,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-arl-cs42l43-l0.tplg",
+ .sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
- .link_mask = BIT(2) | BIT(3),
- .links = arl_cs42l43_l2_cs35l56_l3,
+ .link_mask = BIT(0) | BIT(3),
+ .links = arl_rt711_l0_rt1316_l3,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg",
+ .sof_tplg_filename = "sof-arl-rt711-l0-rt1316-l3.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(3),
+ .links = arl_rt712_l0_rt1320_l3,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-arl-rt712-l0-rt1320-l3.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
- .link_mask = BIT(2),
- .links = arl_cs42l43_l2,
+ .link_mask = BIT(2) | BIT(3),
+ .links = arl_cs42l43_l2_cs35l56_l3,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg",
+ .sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
- .link_mask = BIT(0) | BIT(3),
- .links = arl_rt711_l0_rt1316_l3,
+ .link_mask = BIT(0),
+ .links = arl_cs42l43_l0,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-arl-rt711-l0-rt1316-l3.tplg",
+ .sof_tplg_filename = "sof-arl-cs42l43-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = 0x1, /* link0 required */
@@ -522,10 +563,10 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.sof_tplg_filename = "sof-arl-rt711-l0.tplg",
},
{
- .link_mask = BIT(0) | BIT(2),
- .links = arl_rt722_l0_rt1320_l2,
+ .link_mask = BIT(2),
+ .links = arl_cs42l43_l2,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg",
+ .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{},
diff --git a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
index b8695d47e55b..217272260803 100644
--- a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
@@ -10,7 +10,20 @@
#include <sound/soc-acpi-intel-match.h>
#include "soc-acpi-intel-sdw-mockup-match.h"
+static const struct snd_soc_acpi_codecs nvl_essx_83x6 = {
+ .num_codecs = 3,
+ .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = {
+ {
+ .comp_ids = &nvl_essx_83x6,
+ .drv_name = "sof-essx8336",
+ .sof_tplg_filename = "sof-nvl-es8336", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+ SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+ SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_nvl_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
index 3b7818355ff6..f7694b2a2b02 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
@@ -92,48 +92,6 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
.group_id = 1,
};
-static const struct snd_soc_acpi_endpoint spk_1_endpoint = {
- .num = 0,
- .aggregated = 1,
- .group_position = 1,
- .group_id = 1,
-};
-
-static const struct snd_soc_acpi_endpoint spk_2_endpoint = {
- .num = 0,
- .aggregated = 1,
- .group_position = 2,
- .group_id = 1,
-};
-
-static const struct snd_soc_acpi_endpoint spk_3_endpoint = {
- .num = 0,
- .aggregated = 1,
- .group_position = 3,
- .group_id = 1,
-};
-
-static const struct snd_soc_acpi_endpoint spk_4_endpoint = {
- .num = 0,
- .aggregated = 1,
- .group_position = 4,
- .group_id = 1,
-};
-
-static const struct snd_soc_acpi_endpoint spk_5_endpoint = {
- .num = 0,
- .aggregated = 1,
- .group_position = 5,
- .group_id = 1,
-};
-
-static const struct snd_soc_acpi_endpoint spk_6_endpoint = {
- .num = 0,
- .aggregated = 1,
- .group_position = 6,
- .group_id = 1,
-};
-
static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = {
/* Jack Endpoint */
{
@@ -202,15 +160,6 @@ static const struct snd_soc_acpi_endpoint cs42l43_amp_spkagg_endpoints[] = {
},
};
-static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = {
- {
- .adr = 0x00023001fa424301ull,
- .num_endpoints = ARRAY_SIZE(cs42l43_amp_spkagg_endpoints),
- .endpoints = cs42l43_amp_spkagg_endpoints,
- .name_prefix = "cs42l43"
- }
-};
-
static const struct snd_soc_acpi_adr_device cs42l43_3_agg_adr[] = {
{
.adr = 0x00033001FA424301ull,
@@ -235,48 +184,6 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_lr_adr[] = {
}
};
-static const struct snd_soc_acpi_adr_device cs35l56_1_3amp_adr[] = {
- {
- .adr = 0x00013001fa355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_1_endpoint,
- .name_prefix = "AMP1"
- },
- {
- .adr = 0x00013101fa355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_2_endpoint,
- .name_prefix = "AMP2"
- },
- {
- .adr = 0x00013201fa355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_3_endpoint,
- .name_prefix = "AMP3"
- }
-};
-
-static const struct snd_soc_acpi_adr_device cs35l56_3_3amp_adr[] = {
- {
- .adr = 0x00033301fa355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_4_endpoint,
- .name_prefix = "AMP4"
- },
- {
- .adr = 0x00033401fa355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_5_endpoint,
- .name_prefix = "AMP5"
- },
- {
- .adr = 0x00033501fa355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_6_endpoint,
- .name_prefix = "AMP6"
- }
-};
-
static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
{
.adr = 0x000030025D071101ull,
@@ -408,25 +315,6 @@ static const struct snd_soc_acpi_link_adr ptl_cs42l43_agg_l3_cs35l56_l2[] = {
{}
};
-static const struct snd_soc_acpi_link_adr ptl_cs42l43_l2_cs35l56x6_l13[] = {
- {
- .mask = BIT(2),
- .num_adr = ARRAY_SIZE(cs42l43_2_adr),
- .adr_d = cs42l43_2_adr,
- },
- {
- .mask = BIT(1),
- .num_adr = ARRAY_SIZE(cs35l56_1_3amp_adr),
- .adr_d = cs35l56_1_3amp_adr,
- },
- {
- .mask = BIT(3),
- .num_adr = ARRAY_SIZE(cs35l56_3_3amp_adr),
- .adr_d = cs35l56_3_3amp_adr,
- },
- {}
-};
-
static const struct snd_soc_acpi_link_adr ptl_rt722_l0_rt1320_l23[] = {
{
.mask = BIT(0),
@@ -493,6 +381,20 @@ static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l3_rt1320_l12[] = {
{}
};
+static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l3_rt1320_l1[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt713_vb_3_adr),
+ .adr_d = rt713_vb_3_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1320_1_group2_adr),
+ .adr_d = rt1320_1_group2_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l2_rt1320_l1[] = {
{
.mask = BIT(2),
@@ -579,10 +481,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
- .link_mask = BIT(1) | BIT(2) | BIT(3),
- .links = ptl_cs42l43_l2_cs35l56x6_l13,
+ .link_mask = BIT(1) | BIT(3),
+ .links = ptl_sdw_rt713_vb_l3_rt1320_l1,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-ptl-cs42l43-l2-cs35l56x6-l13.tplg",
+ .sof_tplg_filename = "sof-ptl-rt713-l3-rt1320-l1.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2) | BIT(3),
@@ -611,6 +514,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.link_mask = BIT(2) | BIT(3),
.links = ptl_cs42l43_agg_l3_cs35l56_l2,
.drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_no_function_topology,
.sof_tplg_filename = "sof-ptl-cs42l43-agg-l3-cs35l56-l2.tplg",
},
{
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
index 3eaa058f8460..7caabc501b16 100644
--- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
@@ -6,6 +6,7 @@
*
*/
+#include <linux/dmi.h>
#include <linux/soundwire/sdw_intel.h>
#include <sound/sdca.h>
#include <sound/soc-acpi.h>
@@ -37,6 +38,21 @@ bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg)
}
EXPORT_SYMBOL_NS(snd_soc_acpi_intel_sdca_is_device_rt712_vb, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS");
+static const struct dmi_system_id function_topology_quirk_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ },
+ },
+ {}
+};
+
+bool snd_soc_acpi_intel_no_function_topology(void *arg)
+{
+ return !!dmi_check_system(function_topology_quirk_table);
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_no_function_topology, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS");
+
MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
index bead5ec6243f..2ea0a1881c4b 100644
--- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
@@ -10,5 +10,6 @@
#define _SND_SOC_ACPI_INTEL_SDCA_QUIRKS
bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg);
+bool snd_soc_acpi_intel_no_function_topology(void *arg);
#endif
diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c
index ede19fdea6e9..3a1be41df096 100644
--- a/sound/soc/qcom/qdsp6/q6apm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6apm-dai.c
@@ -497,7 +497,12 @@ static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc
{
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_pcm *pcm = rtd->pcm;
- int size = BUFFER_BYTES_MAX;
+ /*
+ * Allocate one extra page as a workaround for a DSP bug where 32-bit
+ * address arithmetic can overflow when the buffer is placed near the
+ * end of the addressable range.
+ */
+ int size = BUFFER_BYTES_MAX + PAGE_SIZE;
int graph_id, ret;
struct snd_pcm_substream *substream;
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index 1637cc3f3d59..e440c2327100 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -194,6 +194,8 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_type = SOC_SDW_DAI_TYPE_MIC,
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
.rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ .quirk = SOC_SDW_CODEC_MIC,
+ .quirk_exclude = true,
},
},
.dai_num = 3,
@@ -501,6 +503,8 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_type = SOC_SDW_DAI_TYPE_MIC,
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
.rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ .quirk = SOC_SDW_CODEC_MIC,
+ .quirk_exclude = true,
},
},
.dai_num = 3,
@@ -1110,7 +1114,7 @@ int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
struct asoc_sdw_codec_info *codec_info;
struct snd_soc_dai *dai;
struct sdw_slave *sdw_peripheral;
- const char *spk_components="";
+ const char *spk_components = NULL;
int dai_index;
int ret;
int i;
@@ -1193,7 +1197,7 @@ skip_add_controls_widgets:
else
component = codec_info->dais[dai_index].component_name;
- if (strlen (spk_components) == 0)
+ if (!spk_components)
spk_components =
devm_kasprintf(card->dev, GFP_KERNEL, "%s", component);
else
@@ -1201,13 +1205,15 @@ skip_add_controls_widgets:
spk_components =
devm_kasprintf(card->dev, GFP_KERNEL,
"%s+%s", spk_components, component);
+
+ if (!spk_components)
+ return -ENOMEM;
}
codec_info->dais[dai_index].rtd_init_done = true;
-
}
- if (strlen (spk_components) > 0) {
+ if (spk_components) {
/* Update card components for speaker components */
card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s",
card->components, spk_components);
@@ -1608,6 +1614,7 @@ int asoc_sdw_get_dai_type(u32 type)
switch (type) {
case SDCA_FUNCTION_TYPE_SMART_AMP:
case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
+ case SDCA_FUNCTION_TYPE_COMPANION_AMP:
return SOC_SDW_DAI_TYPE_AMP;
case SDCA_FUNCTION_TYPE_SMART_MIC:
case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index c8adfff826bd..9cb7567e263e 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -36,6 +36,7 @@ int snd_soc_ret(const struct device *dev, int ret, const char *fmt, ...)
vaf.va = &args;
dev_err(dev, "ASoC error (%d): %pV", ret, &vaf);
+ va_end(args);
}
return ret;
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index 71a18f156de2..f615b8d1c802 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -223,7 +223,7 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
{
struct snd_sof_dev *sdev = adata->dev;
int ret;
- u32 data;
+ int data;
if (!cmd)
return -EINVAL;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index b3d61d973ce4..8662b422eb80 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1412,7 +1412,8 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
link_mask |= BIT(peripherals->array[i]->bus->link_id);
link_num = hweight32(link_mask);
- links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL);
+ /* An empty adr_link is needed to terminate the adr_link loop */
+ links = devm_kcalloc(sdev->dev, link_num + 1, sizeof(*links), GFP_KERNEL);
if (!links)
return NULL;
diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c
index 1cb99f1abc7c..5420ca2aefbd 100644
--- a/sound/soc/spacemit/k1_i2s.c
+++ b/sound/soc/spacemit/k1_i2s.c
@@ -93,8 +93,8 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s)
u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val;
sscr_val = SSCR_TRAIL | SSCR_FRF_PSP;
- ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 5) |
- FIELD_PREP(SSFCR_FIELD_RFT, 5) |
+ ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 0xF) |
+ FIELD_PREP(SSFCR_FIELD_RFT, 0xF) |
SSFCR_RSRE | SSFCR_TSRE;
ssrwt_val = SSRWT_RWOT;
sspsp_val = SSPSP_SFRMP;
@@ -106,6 +106,37 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s)
writel(0, i2s->base + SSINTEN);
}
+static int spacemit_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 2, 2);
+ snd_pcm_hw_constraint_mask64(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FMTBIT_S16_LE);
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 1, 1);
+ snd_pcm_hw_constraint_mask64(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FMTBIT_S32_LE);
+ break;
+ default:
+ dev_dbg(i2s->dev, "unexpected format type");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -117,10 +148,6 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
u32 val;
int ret;
- val = readl(i2s->base + SSCR);
- if (val & SSCR_SSE)
- return 0;
-
dma_data = &i2s->playback_dma_data;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -157,22 +184,9 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
dma_data->maxburst = 32;
dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
}
-
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- 1, 2);
- snd_pcm_hw_constraint_mask64(substream->runtime,
- SNDRV_PCM_HW_PARAM_FORMAT,
- SNDRV_PCM_FMTBIT_S16_LE);
break;
case SND_SOC_DAIFMT_DSP_A:
case SND_SOC_DAIFMT_DSP_B:
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- 1, 1);
- snd_pcm_hw_constraint_mask64(substream->runtime,
- SNDRV_PCM_HW_PARAM_FORMAT,
- SNDRV_PCM_FMTBIT_S32_LE);
break;
default:
dev_dbg(i2s->dev, "unexpected format type");
@@ -181,6 +195,9 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
}
val = readl(i2s->base + SSCR);
+ if (val & SSCR_SSE)
+ return 0;
+
val &= ~SSCR_DW_32BYTE;
val |= data_width;
writel(val, i2s->base + SSCR);
@@ -303,6 +320,7 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
.probe = spacemit_i2s_dai_probe,
.remove = spacemit_i2s_dai_remove,
+ .startup = spacemit_i2s_startup,
.hw_params = spacemit_i2s_hw_params,
.set_sysclk = spacemit_i2s_set_sysclk,
.set_fmt = spacemit_i2s_set_fmt,
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 3f396c87802e..1c18ef6971c0 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# Tegra platform Support
snd-soc-tegra-pcm-y := tegra_pcm.o
-snd-soc-tegra-utils-y += tegra_asoc_utils.o
snd-soc-tegra20-ac97-y := tegra20_ac97.o
snd-soc-tegra20-das-y := tegra20_das.o
snd-soc-tegra20-i2s-y := tegra20_i2s.o
diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c
index fb92bb88eb5c..f6c393c9489d 100644
--- a/sound/soc/ti/omap-dmic.c
+++ b/sound/soc/ti/omap-dmic.c
@@ -328,7 +328,7 @@ static int omap_dmic_select_fclk(struct omap_dmic *dmic, int clk_id,
}
mux = clk_get_parent(dmic->fclk);
- if (IS_ERR(mux)) {
+ if (!mux) {
dev_err(dmic->dev, "can't get fck mux parent\n");
clk_put(parent_clk);
return -ENODEV;
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 75f82a92ff44..2f5f62079fa4 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -592,6 +592,7 @@ static __u32 reverse_bytes(__u32 b, int len)
fallthrough;
case 2:
b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1);
+ fallthrough;
case 1:
case 0:
break;
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 8af0c04041ee..b20aae0caf60 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -366,7 +366,7 @@ static int setup_card(struct snd_usb_caiaqdev *cdev)
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
ret = snd_usb_caiaq_input_init(cdev);
- if (ret < 0) {
+ if (ret < 0 && ret != -ENODEV) {
dev_err(dev, "Unable to set up input system (ret=%d)\n", ret);
return ret;
}
@@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
cdev = caiaqdev(card);
cdev->chip.dev = usb_get_dev(usb_dev);
+ card->private_free = card_free;
cdev->chip.card = card;
cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct));
@@ -511,10 +512,9 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
cdev->vendor_name, cdev->product_name, usbpath);
- card->private_free = card_free;
err = setup_card(cdev);
if (err < 0)
- return err;
+ goto err_kill_urb;
return 0;
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index a9130891bb69..5c70fdf61cc1 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -804,7 +804,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev)
default:
/* no input methods supported on this device */
- ret = -EINVAL;
+ ret = -ENODEV;
goto exit_free_idev;
}
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 842ba5b801ea..2e0c18e35281 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -208,11 +208,18 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
}
/*
- * MOTU MicroBook IIc
- * Sample rate changes takes more than 2 seconds for this device. Clock
- * validity request returns false during that period.
+ * Quirk for older MOTU AVB / hybrid interfaces
+ *
+ * These devices take more than 2 seconds to switch sample rate or
+ * clock source. During this period the clock validity request
+ * returns false, causing ALSA to fail prematurely.
+ *
+ * Affected models (all use vendor 0x07fd):
+ * - MicroBook IIc → 0x0004
+ * - 1248, 624, 8A, UltraLite AVB, 8M, 16A, ... → 0x0005
*/
- if (chip->usb_id == USB_ID(0x07fd, 0x0004)) {
+ if (chip->usb_id == USB_ID(0x07fd, 0x0004) || /* MicroBook IIc */
+ chip->usb_id == USB_ID(0x07fd, 0x0005)) { /* 1248 / 624 / 8A / UltraLite AVB / ... */
count = 0;
while ((!ret) && (count < 50)) {
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 0a5b8941ebda..d87e3f357cf7 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1951,15 +1951,17 @@ static struct usb_ms_endpoint_descriptor *find_usb_ms_endpoint_descriptor(
while (extralen > 3) {
struct usb_ms_endpoint_descriptor *ms_ep =
(struct usb_ms_endpoint_descriptor *)extra;
+ int length = ms_ep->bLength;
- if (ms_ep->bLength > 3 &&
+ if (!length || length > extralen)
+ break;
+
+ if (length > 3 &&
ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT &&
ms_ep->bDescriptorSubtype == UAC_MS_GENERAL)
return ms_ep;
- if (!extra[0])
- break;
- extralen -= extra[0];
- extra += extra[0];
+ extralen -= length;
+ extra += length;
}
return NULL;
}
diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c
index 3546ba926cb3..04aeb9052f13 100644
--- a/sound/usb/midi2.c
+++ b/sound/usb/midi2.c
@@ -227,7 +227,7 @@ static void kill_midi_urbs(struct snd_usb_midi2_endpoint *ep, bool suspending)
if (!ep)
return;
if (suspending)
- ep->suspended = ep->running;
+ atomic_set(&ep->suspended, atomic_read(&ep->running));
atomic_set(&ep->running, 0);
for (i = 0; i < ep->num_urbs; i++) {
if (!ep->urbs[i].urb)
@@ -496,15 +496,17 @@ static void *find_usb_ms_endpoint_descriptor(struct usb_host_endpoint *hostep,
while (extralen > 3) {
struct usb_ms_endpoint_descriptor *ms_ep =
(struct usb_ms_endpoint_descriptor *)extra;
+ int length = ms_ep->bLength;
- if (ms_ep->bLength > 3 &&
+ if (!length || length > extralen)
+ break;
+
+ if (length > 3 &&
ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT &&
ms_ep->bDescriptorSubtype == subtype)
return ms_ep;
- if (!extra[0])
- break;
- extralen -= extra[0];
- extra += extra[0];
+ extralen -= length;
+ extra += length;
}
return NULL;
}
@@ -1188,10 +1190,11 @@ void snd_usb_midi_v2_suspend_all(struct snd_usb_audio *chip)
static void resume_midi2_endpoint(struct snd_usb_midi2_endpoint *ep)
{
- ep->running = ep->suspended;
- if (ep->direction == STR_IN)
+ atomic_set(&ep->running, atomic_read(&ep->suspended));
+ atomic_set(&ep->suspended, 0);
+
+ if (ep->direction == STR_IN || atomic_read(&ep->running))
submit_io_urbs(ep);
- /* FIXME: does it all? */
}
void snd_usb_midi_v2_resume_all(struct snd_usb_audio *chip)
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 49b3dd8d827d..b9a62e94e06c 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -894,8 +894,9 @@ find_format_descriptor(struct usb_interface *interface)
struct uac_format_type_i_discrete_descriptor *desc;
desc = (struct uac_format_type_i_discrete_descriptor *)extra;
- if (desc->bLength > extralen) {
- dev_err(&interface->dev, "descriptor overflow\n");
+ if (desc->bLength < sizeof(struct usb_descriptor_header) ||
+ desc->bLength > extralen) {
+ dev_err(&interface->dev, "invalid descriptor length\n");
return NULL;
}
if (desc->bLength == UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1) &&
@@ -974,6 +975,13 @@ static int detect_usb_format(struct ua101 *ua)
ua->capture.channels = fmt_capture->bNrChannels;
ua->playback.channels = fmt_playback->bNrChannels;
+ if (!ua->capture.channels || !ua->playback.channels) {
+ dev_err(&ua->dev->dev,
+ "invalid channel count: capture %u, playback %u\n",
+ ua->capture.channels, ua->playback.channels);
+ return -EINVAL;
+ }
+
ua->capture.frame_bytes =
fmt_capture->bSubframeSize * ua->capture.channels;
ua->playback.frame_bytes =
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 85653112e7f3..5fba456eb4a9 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1190,6 +1190,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
cval->res = 1;
}
break;
+
+ case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */
+ case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */
+ if (!strcmp(kctl->id.name, "PCM Playback Volume")) {
+ usb_audio_info(chip,
+ "set volume quirk for PDP Riffmaster for PS4/PS5\n");
+ cval->min = -2560; /* Mute under it */
+ }
+ break;
+
case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */
if (!strcmp(kctl->id.name, "PCM Playback Volume")) {
usb_audio_info(chip,
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
index 8eaa96222759..8e80a7165faf 100644
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -6707,6 +6707,8 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
err = scarlett2_add_new_ctl(
mixer, &scarlett2_autogain_status_ctl,
i, 1, s, &private->autogain_status_ctls[i]);
+ if (err < 0)
+ return err;
}
/* Add autogain target controls */
@@ -9185,12 +9187,15 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw,
flash_size = private->flash_segment_blocks[segment_id] *
SCARLETT2_FLASH_BLOCK_SIZE;
- if (count < 0 || *offset < 0 || *offset + count >= flash_size)
- return -ENOSPC;
+ if (count < 0 || *offset < 0)
+ return -EINVAL;
if (!count)
return 0;
+ if (*offset >= flash_size || count > flash_size - *offset)
+ return -ENOSPC;
+
/* Limit the *req size to SCARLETT2_FLASH_RW_MAX */
if (count > max_data_size)
count = max_data_size;
diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c
index 5f993b88448c..a0009503b2c5 100644
--- a/sound/usb/qcom/qc_audio_offload.c
+++ b/sound/usb/qcom/qc_audio_offload.c
@@ -565,6 +565,7 @@ static unsigned long uaudio_iommu_map_pa(enum mem_type mtype, bool dma_coherent,
unsigned long iova = 0;
bool map = true;
int prot = uaudio_iommu_map_prot(dma_coherent);
+ int ret;
switch (mtype) {
case MEM_EVENT_RING:
@@ -582,10 +583,24 @@ static unsigned long uaudio_iommu_map_pa(enum mem_type mtype, bool dma_coherent,
dev_err(uaudio_qdev->data->dev, "unknown mem type %d\n", mtype);
}
- if (!iova || !map)
+ if (!iova)
return 0;
- iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL);
+ if (!map)
+ return iova;
+
+ ret = iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot,
+ GFP_KERNEL);
+ if (ret) {
+ dev_err(uaudio_qdev->data->dev,
+ "failed to map %zu bytes at iova 0x%08lx: %d\n",
+ size, iova, ret);
+ if (mtype == MEM_XFER_RING)
+ uaudio_put_iova(iova, size,
+ &uaudio_qdev->xfer_ring_list,
+ &uaudio_qdev->xfer_ring_iova_size);
+ return 0;
+ }
return iova;
}
@@ -1054,15 +1069,17 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs,
if (!xfer_buf)
return -ENOMEM;
- dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf,
- xfer_buf_dma, len);
+ ret = dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf,
+ xfer_buf_dma, len);
+ if (ret)
+ goto free_xfer_buf;
/* map the physical buffer into sysdev as well */
xfer_buf_dma_sysdev = uaudio_iommu_map_xfer_buf(dma_coherent,
len, &xfer_buf_sgt);
if (!xfer_buf_dma_sysdev) {
ret = -ENOMEM;
- goto unmap_sync;
+ goto free_sgt;
}
mem_info->dma = xfer_buf_dma;
@@ -1073,7 +1090,9 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs,
return 0;
-unmap_sync:
+free_sgt:
+ sg_free_table(&xfer_buf_sgt);
+free_xfer_buf:
usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_dma);
return ret;
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 803e03d4d77b..4e9cfff4047f 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2652,6 +2652,9 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+
+#endif /* disabled */
+
{
/*
* The AudioBox USB advertises S24_3LE as the only supported format
@@ -2700,7 +2703,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
-#endif /* disabled */
{
/*
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 7b803ad58487..31cbe383ae65 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -125,7 +125,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,
snd_usb_audioformat_set_sync_ep(chip, fp);
- err = snd_usb_add_audio_stream(chip, stream, fp);
+ err = snd_usb_add_audio_stream(chip, stream, fp, NULL);
if (err < 0)
return err;
@@ -2277,6 +2277,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_ALIGN_TRANSFER),
DEVICE_FLG(0x05e1, 0x0480, /* Hauppauge Woodbury */
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x05fc, 0x0231, /* JBL Pebbles */
+ QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL | QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL |
+ QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x0624, 0x3d3f, /* AB13X USB Audio */
QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
DEVICE_FLG(0x0644, 0x8043, /* TEAC UD-501/UD-501V2/UD-503/NT-503 */
@@ -2366,6 +2369,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x152a, 0x880a, /* NeuralDSP Quad Cortex */
0), /* Doesn't have the vendor quirk which would otherwise apply */
+ DEVICE_FLG(0x1532, 0x055e, /* Razer Nommo V2 X */
+ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
DEVICE_FLG(0x154e, 0x1002, /* Denon DCD-1500RE */
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
DEVICE_FLG(0x154e, 0x1003, /* Denon DA-300USB */
@@ -2458,6 +2463,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_GENERIC_IMPLICIT_FB),
DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x2b73, 0x0047, /* AlphaTheta EUPHONIA */
+ QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
DEVICE_FLG(0x2d95, 0x8011, /* VIVO USB-C HEADSET */
QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x2d95, 0x8021, /* VIVO USB-C-XE710 HEADSET */
@@ -2472,6 +2479,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x3255, 0x0000, /* Luxman D-10X */
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
+ DEVICE_FLG(0x3302, 0x17c2, /* TTGK Technology USB-C Audio */
+ QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */
QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
DEVICE_FLG(0x3443, 0x930d, /* NexiGo N930W 60fps Webcam */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 2532bf97e05e..b2c5c8198281 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
static void snd_usb_init_substream(struct snd_usb_stream *as,
int stream,
struct audioformat *fp,
- struct snd_usb_power_domain *pd)
+ struct snd_usb_power_domain **pdptr)
{
struct snd_usb_substream *subs = &as->substream[stream];
@@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
if (fp->channels > subs->channels_max)
subs->channels_max = fp->channels;
- if (pd) {
- subs->str_pd = pd;
+ if (pdptr && *pdptr) {
+ subs->str_pd = *pdptr;
+ *pdptr = NULL; /* assigned */
/* Initialize Power Domain to idle status D1 */
- snd_usb_power_domain_set(subs->stream->chip, pd,
+ snd_usb_power_domain_set(subs->stream->chip, subs->str_pd,
UAC3_PD_STATE_D1);
}
@@ -352,6 +353,8 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
if (len < sizeof(*cs_desc))
break;
cs_len = le16_to_cpu(cs_desc->wLength);
+ if (cs_len < sizeof(*cs_desc))
+ break;
if (len < cs_len)
break;
cs_type = cs_desc->bSegmentType;
@@ -492,11 +495,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
* if not, create a new pcm stream. note, fp is added to the substream
* fmt_list and will be freed on the chip instance release. do not free
* fp or do remove it from the substream fmt_list to avoid double-free.
+ *
+ * pdptr is optional and can be NULL. When it's non-NULL and the PD gets
+ * assigned to the stream, *pdptr is cleared to NULL upon return.
*/
-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp,
- struct snd_usb_power_domain *pd)
+int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
+ int stream,
+ struct audioformat *fp,
+ struct snd_usb_power_domain **pdptr)
{
struct snd_usb_stream *as;
@@ -529,7 +535,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
err = snd_pcm_new_stream(as->pcm, stream, 1);
if (err < 0)
return err;
- snd_usb_init_substream(as, stream, fp, pd);
+ snd_usb_init_substream(as, stream, fp, pdptr);
return add_chmap(as->pcm, stream, subs);
}
@@ -558,7 +564,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
else
strscpy(pcm->name, "USB Audio");
- snd_usb_init_substream(as, stream, fp, pd);
+ snd_usb_init_substream(as, stream, fp, pdptr);
/*
* Keep using head insertion for M-Audio Audiophile USB (tm) which has a
@@ -576,21 +582,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
return add_chmap(pcm, stream, &as->substream[stream]);
}
-int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp)
-{
- return __snd_usb_add_audio_stream(chip, stream, fp, NULL);
-}
-
-static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp,
- struct snd_usb_power_domain *pd)
-{
- return __snd_usb_add_audio_stream(chip, stream, fp, pd);
-}
-
static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
struct usb_host_interface *alts,
int protocol, int iface_no)
@@ -1003,7 +994,7 @@ 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))
+ if (wLength < sizeof(*cluster))
return NULL;
cluster = kzalloc(wLength, GFP_KERNEL);
if (!cluster)
@@ -1113,8 +1104,7 @@ found_clock:
}
}
- if (pd)
- *pd_out = pd;
+ *pd_out = pd;
return fp;
}
@@ -1129,7 +1119,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
struct usb_interface_descriptor *altsd;
int i, altno, err, stream;
struct audioformat *fp = NULL;
- struct snd_usb_power_domain *pd = NULL;
bool set_iface_first;
int num, protocol;
@@ -1171,6 +1160,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
continue;
+ /* pd may be allocated at snd_usb_get_audioformat_uac3() and
+ * assigned at snd_usb_add_audio_stream(); otherwise it'll be
+ * freed automatically by cleanup at each loop.
+ */
+ struct snd_usb_power_domain *pd __free(kfree) = NULL;
+
/*
* Roland audio streaming interfaces are marked with protocols
* 0/1/2, but are UAC 1 compatible.
@@ -1226,23 +1221,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
*has_non_pcm = true;
if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) {
audioformat_free(fp);
- kfree(pd);
fp = NULL;
- pd = NULL;
continue;
}
snd_usb_audioformat_set_sync_ep(chip, fp);
dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
- if (protocol == UAC_VERSION_3)
- err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd);
- else
- err = snd_usb_add_audio_stream(chip, stream, fp);
-
+ err = snd_usb_add_audio_stream(chip, stream, fp, &pd);
if (err < 0) {
audioformat_free(fp);
- kfree(pd);
return err;
}
diff --git a/sound/usb/stream.h b/sound/usb/stream.h
index d92e18d5818f..61b9a133da01 100644
--- a/sound/usb/stream.h
+++ b/sound/usb/stream.h
@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
int stream,
- struct audioformat *fp);
+ struct audioformat *fp,
+ struct snd_usb_power_domain **pdptr);
#endif /* __USBAUDIO_STREAM_H */