diff options
| -rw-r--r-- | sound/soc/soc-pcm.c | 52 |
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; |
