summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/soc-pcm.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 7c441a06a13d..69c764c6fe42 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -25,6 +25,7 @@
#include <linux/workqueue.h>
#include <linux/export.h>
#include <linux/debugfs.h>
+#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -52,6 +53,21 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream)
return codec_stream->rates;
}
+static const struct snd_pcm_hardware no_host_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = PAGE_SIZE >> 2,
+ .period_bytes_max = PAGE_SIZE >> 1,
+ .periods_min = 2,
+ .periods_max = 4,
+ .buffer_bytes_max = PAGE_SIZE,
+};
+
/**
* snd_soc_runtime_activate() - Increment active count for PCM runtime components
* @rtd: ASoC PCM runtime that is activated
@@ -156,6 +172,8 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ if (!runtime)
+ return 0;
runtime->hw.info = hw->info;
runtime->hw.formats = hw->formats;
runtime->hw.period_bytes_min = hw->period_bytes_min;
@@ -467,6 +485,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
pm_runtime_get_sync(platform->dev);
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+ if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
+ snd_soc_set_runtime_hwparams(substream, &no_host_hardware);
/* startup the audio subsystem */
if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) {
@@ -916,6 +936,19 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
cpu_dai->channels = params_channels(params);
cpu_dai->sample_bits =
snd_pcm_format_physical_width(params_format(params));
+ /* malloc a page for hostless IO.
+ * FIXME: rework with alsa-lib changes so that this malloc is not required.
+ */
+ if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) {
+ substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV;
+ substream->dma_buffer.dev.dev = rtd->dev;
+ substream->dma_buffer.dev.dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ substream->dma_buffer.private_data = NULL;
+
+ ret = snd_pcm_lib_malloc_pages(substream, PAGE_SIZE);
+ if (ret < 0)
+ goto platform_err;
+ }
out:
mutex_unlock(&rtd->pcm_mutex);
@@ -999,6 +1032,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
+ if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
+ snd_pcm_lib_free_pages(substream);
+
mutex_unlock(&rtd->pcm_mutex);
return 0;
}
@@ -2611,6 +2647,22 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
goto out;
}
+ /* setup any hostless PCMs - i.e. no host IO is performed */
+ if (rtd->dai_link->no_host_mode) {
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->hw_no_buffer = 1;
+ snd_soc_set_runtime_hwparams(
+ pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
+ &no_host_hardware);
+ }
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->hw_no_buffer = 1;
+ snd_soc_set_runtime_hwparams(
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+ &no_host_hardware);
+ }
+ }
+
/* ASoC PCM operations */
if (rtd->dai_link->dynamic) {
rtd->ops.open = dpcm_fe_dai_open;