soundwire: stream: add helper to startup/shutdown streams

To handle streams at the dailink level, expose two helpers that will
be called from machine drivers.

Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20200630184356.24939-3-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
Pierre-Louis Bossart 2020-07-01 02:43:53 +08:00 committed by Vinod Koul
parent 09553140c8
commit 4550569bd7
3 changed files with 110 additions and 1 deletions

View File

@ -293,6 +293,10 @@ per stream. From ASoC DPCM framework, this stream state maybe linked to
int sdw_alloc_stream(char * stream_name); int sdw_alloc_stream(char * stream_name);
The SoundWire core provides a sdw_startup_stream() helper function,
typically called during a dailink .startup() callback, which performs
stream allocation and sets the stream pointer for all DAIs
connected to a stream.
SDW_STREAM_CONFIGURED SDW_STREAM_CONFIGURED
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
@ -509,7 +513,12 @@ In .shutdown() the data structure maintaining stream state are freed up.
void sdw_release_stream(struct sdw_stream_runtime * stream); void sdw_release_stream(struct sdw_stream_runtime * stream);
Not Supported The SoundWire core provides a sdw_shutdown_stream() helper function,
typically called during a dailink .shutdown() callback, which clears
the stream pointer for all DAIS connected to a stream and releases the
memory allocated for the stream.
Not Supported
============= =============
1. A single port with multiple channels supported cannot be used between two 1. A single port with multiple channels supported cannot be used between two

View File

@ -13,6 +13,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw.h>
#include <sound/soc.h>
#include "bus.h" #include "bus.h"
/* /*
@ -1826,3 +1827,100 @@ state_err:
return ret; return ret;
} }
EXPORT_SYMBOL(sdw_deprepare_stream); EXPORT_SYMBOL(sdw_deprepare_stream);
static int set_stream(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sdw_stream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *dai;
int ret = 0;
int i;
/* Set stream pointer on all DAIs */
for_each_rtd_dais(rtd, i, dai) {
ret = snd_soc_dai_set_sdw_stream(dai, sdw_stream, substream->stream);
if (ret < 0) {
dev_err(rtd->dev, "failed to set stream pointer on dai %s", dai->name);
break;
}
}
return ret;
}
/**
* sdw_startup_stream() - Startup SoundWire stream
*
* @stream: Soundwire stream
*
* Documentation/driver-api/soundwire/stream.rst explains this API in detail
*/
int sdw_startup_stream(void *sdw_substream)
{
struct snd_pcm_substream *substream = sdw_substream;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sdw_stream_runtime *sdw_stream;
char *name;
int ret;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
name = kasprintf(GFP_KERNEL, "%s-Playback", substream->name);
else
name = kasprintf(GFP_KERNEL, "%s-Capture", substream->name);
if (!name)
return -ENOMEM;
sdw_stream = sdw_alloc_stream(name);
if (!sdw_stream) {
dev_err(rtd->dev, "alloc stream failed for substream DAI %s", substream->name);
ret = -ENOMEM;
goto error;
}
ret = set_stream(substream, sdw_stream);
if (ret < 0)
goto release_stream;
return 0;
release_stream:
sdw_release_stream(sdw_stream);
set_stream(substream, NULL);
error:
kfree(name);
return ret;
}
EXPORT_SYMBOL(sdw_startup_stream);
/**
* sdw_shutdown_stream() - Shutdown SoundWire stream
*
* @stream: Soundwire stream
*
* Documentation/driver-api/soundwire/stream.rst explains this API in detail
*/
void sdw_shutdown_stream(void *sdw_substream)
{
struct snd_pcm_substream *substream = sdw_substream;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sdw_stream_runtime *sdw_stream;
struct snd_soc_dai *dai;
/* Find stream from first CPU DAI */
dai = asoc_rtd_to_cpu(rtd, 0);
sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream);
if (!sdw_stream) {
dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
return;
}
/* release memory */
kfree(sdw_stream->name);
sdw_release_stream(sdw_stream);
/* clear DAI data */
set_stream(substream, NULL);
}
EXPORT_SYMBOL(sdw_shutdown_stream);

View File

@ -955,10 +955,12 @@ int sdw_stream_remove_master(struct sdw_bus *bus,
struct sdw_stream_runtime *stream); struct sdw_stream_runtime *stream);
int sdw_stream_remove_slave(struct sdw_slave *slave, int sdw_stream_remove_slave(struct sdw_slave *slave,
struct sdw_stream_runtime *stream); struct sdw_stream_runtime *stream);
int sdw_startup_stream(void *sdw_substream);
int sdw_prepare_stream(struct sdw_stream_runtime *stream); int sdw_prepare_stream(struct sdw_stream_runtime *stream);
int sdw_enable_stream(struct sdw_stream_runtime *stream); int sdw_enable_stream(struct sdw_stream_runtime *stream);
int sdw_disable_stream(struct sdw_stream_runtime *stream); int sdw_disable_stream(struct sdw_stream_runtime *stream);
int sdw_deprepare_stream(struct sdw_stream_runtime *stream); int sdw_deprepare_stream(struct sdw_stream_runtime *stream);
void sdw_shutdown_stream(void *sdw_substream);
int sdw_bus_prep_clk_stop(struct sdw_bus *bus); int sdw_bus_prep_clk_stop(struct sdw_bus *bus);
int sdw_bus_clk_stop(struct sdw_bus *bus); int sdw_bus_clk_stop(struct sdw_bus *bus);
int sdw_bus_exit_clk_stop(struct sdw_bus *bus); int sdw_bus_exit_clk_stop(struct sdw_bus *bus);