diff --git a/include/sound/soc.h b/include/sound/soc.h index dc3dcad05929..f213d39d7c3c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -380,6 +380,10 @@ #define SND_SOC_COMP_ORDER_LATE 1 #define SND_SOC_COMP_ORDER_LAST 2 +/* DAI Link Host Mode Support */ +#define SND_SOC_DAI_LINK_NO_HOST 0x1 +#define SND_SOC_DAI_LINK_OPT_HOST 0x2 + /* * Bias levels * @@ -976,6 +980,12 @@ struct snd_soc_dai_link { /* This DAI link can route to other DAI links at runtime (Frontend)*/ unsigned int dynamic:1; + /* + * This DAI can support no host IO (no pcm data is + * copied to from host) + */ + unsigned int no_host_mode:2; + /* DPCM capture and Playback support */ unsigned int dpcm_capture:1; unsigned int dpcm_playback:1; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 356d4e754561..d07d323d8dcb 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -28,6 +28,25 @@ #define DPCM_MAX_BE_USERS 8 +/* + * ASoC no host IO hardware. + * TODO: fine tune these values for all host less transfers. + */ +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_dai_stream_valid() - check if a DAI supports the given stream * @@ -493,6 +512,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) 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->startup) { ret = cpu_dai->driver->ops->startup(substream, cpu_dai); @@ -1007,6 +1029,20 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ret = soc_pcm_params_symmetry(substream, params); if (ret) goto component_err; + + /* 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.private_data = NULL; + + ret = snd_pcm_lib_malloc_pages(substream, PAGE_SIZE); + if (ret < 0) + goto component_err; + } out: mutex_unlock(&rtd->pcm_mutex); return ret; @@ -1089,6 +1125,8 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) if (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; } @@ -3150,6 +3188,18 @@ 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) { + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->hw_no_buffer = 1; + pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->hw_no_buffer = 1; + snd_soc_set_runtime_hwparams( + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, + &no_host_hardware); + 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;