aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
authorMark Brown <broonie@kernel.org>2026-05-29 23:13:28 +0100
committerMark Brown <broonie@kernel.org>2026-05-29 23:13:28 +0100
commit9806d07c2f5635f9ae268f1200ee4a1a159b0e17 (patch)
tree3eb048cc42b2a8cbe1b45eee1af7a0f0ea2e472e /drivers
parent18b0a5c1b8f9ef4b603cb9334a731ad04e3a88e5 (diff)
parent8a7fe10eec64bfb7cf4091bca540de4c55d56bfa (diff)
downloadlinux-next-history-9806d07c2f5635f9ae268f1200ee4a1a159b0e17.tar.gz
Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire.git
Diffstat (limited to 'drivers')
-rw-r--r--drivers/soundwire/generic_bandwidth_allocation.c44
-rw-r--r--drivers/soundwire/intel.c31
-rw-r--r--drivers/soundwire/intel_ace2x.c40
-rw-r--r--drivers/soundwire/intel_auxdevice.c3
-rw-r--r--drivers/soundwire/slave.c4
-rw-r--r--drivers/soundwire/stream.c13
6 files changed, 71 insertions, 64 deletions
diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index fb3970e12dac9..3575d69ce1c50 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -299,39 +299,35 @@ static int sdw_add_element_group_count(struct sdw_group *group,
int num = group->count;
int i;
- for (i = 0; i <= num; i++) {
+ for (i = 0; i < num; i++) {
if (rate == group->rates[i] && lane == group->lanes[i])
- break;
-
- if (i != num)
- continue;
+ return 0;
+ }
- if (group->count >= group->max_size) {
- unsigned int *rates;
- unsigned int *lanes;
+ if (group->count >= group->max_size) {
+ unsigned int *rates;
+ unsigned int *lanes;
- group->max_size += 1;
- rates = krealloc(group->rates,
- (sizeof(int) * group->max_size),
- GFP_KERNEL);
- if (!rates)
- return -ENOMEM;
+ rates = krealloc_array(group->rates, group->max_size + 1,
+ sizeof(*group->rates), GFP_KERNEL);
+ if (!rates)
+ return -ENOMEM;
- group->rates = rates;
+ group->rates = rates;
- lanes = krealloc(group->lanes,
- (sizeof(int) * group->max_size),
- GFP_KERNEL);
- if (!lanes)
- return -ENOMEM;
+ lanes = krealloc_array(group->lanes, group->max_size + 1,
+ sizeof(*group->lanes), GFP_KERNEL);
+ if (!lanes)
+ return -ENOMEM;
- group->lanes = lanes;
- }
+ group->lanes = lanes;
- group->rates[group->count] = rate;
- group->lanes[group->count++] = lane;
+ group->max_size += 1;
}
+ group->rates[group->count] = rate;
+ group->lanes[group->count++] = lane;
+
return 0;
}
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index dcd7440e78fa6..af65214836b4d 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -906,19 +906,6 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn
}
switch (cmd) {
- case SNDRV_PCM_TRIGGER_SUSPEND:
-
- /*
- * The .prepare callback is used to deal with xruns and resume operations.
- * In the case of xruns, the DMAs and SHIM registers cannot be touched,
- * but for resume operations the DMAs and SHIM registers need to be initialized.
- * the .trigger callback is used to track the suspend case only.
- */
-
- dai_runtime->suspended = true;
-
- break;
-
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dai_runtime->paused = true;
break;
@@ -955,10 +942,12 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)
struct snd_soc_dai *dai;
/*
- * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
- * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
- * Since the component suspend is called last, we can trap this corner case
- * and force the DAIs to release their resources.
+ * Mark all open streams as suspended.
+ * Open streams at this point can be in SUSPENDED, PAUSED or STOPPED
+ * state and during prepare the DMAs and SHIM registers need to be
+ * initialized for them.
+ * The STOPPED state is a special corner case which can happen if audio
+ * experiences xrun at suspend time.
*/
for_each_component_dais(component, dai) {
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
@@ -966,13 +955,7 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)
dai_runtime = cdns->dai_runtime_array[dai->id];
- if (!dai_runtime)
- continue;
-
- if (dai_runtime->suspended)
- continue;
-
- if (dai_runtime->paused)
+ if (dai_runtime)
dai_runtime->suspended = true;
}
diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c
index 20422534baf19..b37933efac5d2 100644
--- a/drivers/soundwire/intel_ace2x.c
+++ b/drivers/soundwire/intel_ace2x.c
@@ -317,6 +317,7 @@ static void intel_ace2x_bpt_close_stream(struct sdw_intel *sdw, struct sdw_slave
dev_err(cdns->dev, "%s: remove slave failed: %d\n",
__func__, ret);
+ sdw_release_stream(cdns->bus.bpt_stream);
cdns->bus.bpt_stream = NULL;
}
@@ -894,19 +895,6 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn
}
switch (cmd) {
- case SNDRV_PCM_TRIGGER_SUSPEND:
-
- /*
- * The .prepare callback is used to deal with xruns and resume operations.
- * In the case of xruns, the DMAs and SHIM registers cannot be touched,
- * but for resume operations the DMAs and SHIM registers need to be initialized.
- * the .trigger callback is used to track the suspend case only.
- */
-
- dai_runtime->suspended = true;
-
- break;
-
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dai_runtime->paused = true;
break;
@@ -930,8 +918,34 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
.get_stream = intel_get_sdw_stream,
};
+static int intel_component_dais_suspend(struct snd_soc_component *component)
+{
+ struct snd_soc_dai *dai;
+
+ /*
+ * Mark all open streams as suspended.
+ * Open streams at this point can be in SUSPENDED, PAUSED or STOPPED
+ * state and during prepare the DMAs and SHIM registers need to be
+ * initialized for them.
+ * The STOPPED state is a special corner case which can happen if audio
+ * experiences xrun at suspend time.
+ */
+ for_each_component_dais(component, dai) {
+ struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
+ struct sdw_cdns_dai_runtime *dai_runtime;
+
+ dai_runtime = cdns->dai_runtime_array[dai->id];
+
+ if (dai_runtime)
+ dai_runtime->suspended = true;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_component_driver dai_component = {
.name = "soundwire",
+ .suspend = intel_component_dais_suspend,
};
/*
diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c
index 913e95207ee1a..0b8107bec9abe 100644
--- a/drivers/soundwire/intel_auxdevice.c
+++ b/drivers/soundwire/intel_auxdevice.c
@@ -51,6 +51,8 @@ struct wake_capable_part {
};
static struct wake_capable_part wake_capable_list[] = {
+ {0x01fa, 0x2A30},
+ {0x01fa, 0x2A3B},
{0x01fa, 0x4243},
{0x01fa, 0x4245},
{0x01fa, 0x4249},
@@ -70,6 +72,7 @@ static struct wake_capable_part wake_capable_list[] = {
{0x025d, 0x717},
{0x025d, 0x721},
{0x025d, 0x722},
+ {0x04b3, 0x9356},
};
static bool is_wake_capable(struct sdw_slave *slave)
diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
index ff763b692078d..e0c49cbcb1bab 100644
--- a/drivers/soundwire/slave.c
+++ b/drivers/soundwire/slave.c
@@ -244,8 +244,8 @@ int sdw_of_find_slaves(struct sdw_bus *bus)
struct sdw_slave_id id;
const __be32 *addr;
- compat = of_get_property(node, "compatible", NULL);
- if (!compat)
+ ret = of_property_read_string(node, "compatible", &compat);
+ if (ret)
continue;
ret = sscanf(compat, "sdw%01x%04hx%04hx%02hhx", &sdw_version,
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 4ed8fb7663ad4..cdac009b1a756 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -697,6 +697,13 @@ static int sdw_program_params(struct sdw_bus *bus, bool prepare)
if (scale_index < 0)
return scale_index;
+ /* Skip the unattached Peripherals */
+ if (!completion_done(&slave->enumeration_complete)) {
+ dev_warn(&slave->dev,
+ "Not enumerated, skip programming BUSCLOCK_SCALE\n");
+ continue;
+ }
+
ret = sdw_write_no_pm(slave, addr1, scale_index);
if (ret < 0) {
dev_err(&slave->dev, "SDW_SCP_BUSCLOCK_SCALE register write failed\n");
@@ -2229,11 +2236,15 @@ EXPORT_SYMBOL(sdw_stream_add_slave);
* @slave: SDW Slave instance
* @stream: SoundWire stream
*
- * This removes and frees port_rt and slave_rt from a stream
+ * This removes and frees port_rt and slave_rt from a stream.
+ * If stream is NULL or an ERR_PTR, do nothing and return 0.
*/
int sdw_stream_remove_slave(struct sdw_slave *slave,
struct sdw_stream_runtime *stream)
{
+ if (IS_ERR_OR_NULL(stream))
+ return 0;
+
mutex_lock(&slave->bus->bus_lock);
sdw_slave_port_free(slave, stream);